public async Task CustomMessageHandler_WithContextFilter_UsesMessageTypeDuringSelection() { // Arrange var spyHandler = new StubTestMessageHandler <Purchase, MessageContext>(); var collection = new MessageHandlerCollection(new ServiceCollection()); collection.WithMessageHandler <StubTestMessageHandler <Order, MessageContext>, Order>(); collection.WithMessageHandler <StubTestMessageHandler <Purchase, TestMessageContext>, Purchase, TestMessageContext>(); collection.WithMessageHandler <StubTestMessageHandler <Purchase, MessageContext>, Purchase>(provider => spyHandler); IServiceProvider serviceProvider = collection.Services.BuildServiceProvider(); var router = new TestMessageRouter(serviceProvider, _logger); var purchase = new Purchase { CustomerName = _bogusGenerator.Name.FullName(), Price = _bogusGenerator.Commerce.Price() }; string purchaseJson = JsonConvert.SerializeObject(purchase); var context = new MessageContext("message-id", new Dictionary <string, object>()); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); // Act await router.RouteMessageAsync(purchaseJson, context, correlationInfo, CancellationToken.None); // Assert Assert.True(spyHandler.IsProcessed); }
/// <summary> /// Handle the original <paramref name="message"/> that was received through an registered <see cref="IFallbackMessageHandler"/>. /// </summary> /// <param name="message">The message that was received.</param> /// <param name="messageContext">The context providing more information concerning the processing.</param> /// <param name="correlationInfo">The information concerning correlation of telemetry and processes by using a variety of unique identifiers.</param> /// <param name="cancellationToken">The token to cancel the message processing.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the <paramref name="messageContext"/>, or <paramref name="correlationInfo"/> is <c>null</c>. /// </exception> /// <returns> /// [true] if the received <paramref name="message"/> was handled by the registered <see cref="IFallbackMessageHandler"/>; [false] otherwise. /// </returns> protected async Task <bool> TryFallbackProcessMessageAsync <TMessageContext>( string message, TMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) where TMessageContext : MessageContext { Guard.NotNull(messageContext, nameof(messageContext), "Requires a message context to send to the message handler"); Guard.NotNull(correlationInfo, nameof(correlationInfo), "Requires correlation information to send to the message handler"); if (HasFallbackMessageHandler) { string fallbackMessageHandlerTypeName = _fallbackMessageHandler.Value.GetType().Name; Logger.LogTrace("Fallback on registered '{FallbackMessageHandlerType}' because none of the message handlers were able to process the message", fallbackMessageHandlerTypeName); Task processMessageAsync = _fallbackMessageHandler.Value.ProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); if (processMessageAsync is null) { throw new InvalidOperationException( $"Cannot fallback upon the fallback message handler '{fallbackMessageHandlerTypeName}' " + "because the handler was not correctly implemented to process the message as it returns 'null' for its asynchronous operation"); } await processMessageAsync; Logger.LogTrace("Fallback message handler '{FallbackMessageHandlerType}' has processed the message", fallbackMessageHandlerTypeName); return(true); } return(false); }
public async Task CustomMessageHandlerFactory_WithCustomContext_SubtractsRegistration() { // Arrange var spyHandler = new TestMessageHandler(); var collection = new MessageHandlerCollection(new ServiceCollection()); collection.WithMessageHandler <TestMessageHandler, TestMessage, TestMessageContext>(provider => spyHandler); IServiceProvider serviceProvider = collection.Services.BuildServiceProvider(); // Act IEnumerable <MessageHandler> messageHandlers = MessageHandler.SubtractFrom(serviceProvider, _logger); // Assert MessageHandler messageHandler = Assert.Single(messageHandlers); Assert.NotNull(messageHandler); var message = new TestMessage(); var context = TestMessageContext.Generate(); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); await messageHandler.ProcessMessageAsync(message, context, correlationInfo, CancellationToken.None); Assert.True(spyHandler.IsProcessed); }
/// <summary> /// Handle a new <paramref name="message"/> that was received by routing them through registered <see cref="IMessageHandler{TMessage,TMessageContext}"/>s /// and optionally through an registered <see cref="IFallbackMessageHandler"/> if none of the message handlers were able to process the <paramref name="message"/>. /// </summary> /// <param name="message">The message that was received.</param> /// <param name="messageContext">The context providing more information concerning the processing.</param> /// <param name="correlationInfo">The information concerning correlation of telemetry and processes by using a variety of unique identifiers.</param> /// <param name="cancellationToken">The token to cancel the message processing.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the <paramref name="message"/>, <paramref name="messageContext"/>, or <paramref name="correlationInfo"/> is <c>null</c>. /// </exception> /// <exception cref="InvalidOperationException">Thrown when no message handlers or none matching message handlers are found to process the message.</exception> public virtual async Task RouteMessageAsync <TMessageContext>( string message, TMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) where TMessageContext : MessageContext { Guard.NotNull(message, nameof(message), "Requires message content to deserialize and process the message"); Guard.NotNull(messageContext, nameof(messageContext), "Requires a message context to send to the message handler"); Guard.NotNull(correlationInfo, nameof(correlationInfo), "Requires correlation information to send to the message handler"); bool isProcessed = await TryProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); if (isProcessed) { return; } bool isFallbackProcessed = await TryFallbackProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); if (!isFallbackProcessed) { throw new InvalidOperationException( $"Message pump cannot correctly process the message in the '{typeof(TMessageContext).Name}' " + "because none of the registered 'IMessageHandler<,>' implementations in the dependency injection container matches the incoming message type and context. " + $"Make sure you call the correct '.With...' extension on the {nameof(IServiceCollection)} during the registration of the message pump or message router to register a message handler"); } }
public OrderCreatedEventData(string id, int amount, string articleNumber, MessageCorrelationInfo correlationInfo) { Id = id; Amount = amount; ArticleNumber = articleNumber; CorrelationInfo = correlationInfo; }
private async Task <bool> TryProcessMessageAsync <TMessageContext>( string message, TMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) where TMessageContext : MessageContext { MessageHandler[] handlers = GetRegisteredMessageHandlers().ToArray(); if (handlers.Length <= 0 && _fallbackMessageHandler.Value is null) { throw new InvalidOperationException( $"Message pump cannot correctly process the message in the '{typeof(TMessageContext).Name}' " + "because no 'IMessageHandler<,>' was registered in the dependency injection container. " + $"Make sure you call the correct '.With...' extension on the {nameof(IServiceCollection)} during the registration of the message pump or message router to register a message handler"); } foreach (MessageHandler handler in handlers) { MessageResult result = await DeserializeMessageForHandlerAsync(message, messageContext, handler); if (result.IsSuccess) { await handler.ProcessMessageAsync(result.DeserializedMessage, messageContext, correlationInfo, cancellationToken); return(true); } } return(false); }
public async Task WithServiceBusRouting_WithMessageHandlerMessageBodySerializerSubType_DeserializesCustomMessage() { // Arrange var services = new ServiceCollection(); var collection = new ServiceBusMessageHandlerCollection(services); var ignoredHandler = new StubServiceBusMessageHandler <TestMessage>(); var spyHandler = new StubServiceBusMessageHandler <Order>(); var expectedMessage = new TestMessage { TestProperty = "Some value" }; string expectedBody = JsonConvert.SerializeObject(expectedMessage); var serializer = new TestMessageBodySerializer(expectedBody, new SubOrder()); collection.WithServiceBusMessageHandler <StubServiceBusMessageHandler <Order>, Order>(messageBodySerializer: serializer, implementationFactory: serviceProvider => spyHandler) .WithServiceBusMessageHandler <StubServiceBusMessageHandler <TestMessage>, TestMessage>(implementationFactory: serviceProvider => ignoredHandler); // Act services.AddServiceBusMessageRouting(); // Assert IServiceProvider provider = services.BuildServiceProvider(); var router = provider.GetRequiredService <IAzureServiceBusMessageRouter>(); AzureServiceBusMessageContext context = AzureServiceBusMessageContextFactory.Generate(); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); ServiceBusReceivedMessage message = expectedMessage.AsServiceBusReceivedMessage(); await router.RouteMessageAsync(message, context, correlationInfo, CancellationToken.None); Assert.True(spyHandler.IsProcessed); Assert.False(ignoredHandler.IsProcessed); }
/// <summary> /// Tries to process the unhandled <paramref name="message"/> through an potential registered <see cref="IAzureServiceBusFallbackMessageHandler"/> instance. /// </summary> /// <param name="messageReceiver"> /// The instance that can receive Azure Service Bus <see cref="ServiceBusReceivedMessage"/>; used within <see cref="IAzureServiceBusFallbackMessageHandler"/>s with Azure Service Bus specific operations. /// </param> /// <param name="message">The message that was received by the <paramref name="messageReceiver"/>.</param> /// <param name="messageContext">The context in which the <paramref name="message"/> should be processed.</param> /// <param name="correlationInfo">The information concerning correlation of telemetry and processes by using a variety of unique identifiers.</param> /// <param name="cancellationToken">The token to cancel the message processing.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the <paramref name="messageReceiver"/>, <paramref name="message"/>, <paramref name="messageContext"/>, or <paramref name="correlationInfo"/> is <c>null</c>. /// </exception> protected async Task TryServiceBusFallbackMessageAsync( ServiceBusReceiver messageReceiver, ServiceBusReceivedMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Guard.NotNull(message, nameof(message), "Requires an Azure Service Bus message to be processed by the registered fallback message handler"); Guard.NotNull(messageContext, nameof(messageContext), "Requires an Azure Service Bus message context in which the incoming message can be processed"); Guard.NotNull(correlationInfo, nameof(correlationInfo), "Requires an correlation information to correlate between incoming Azure Service Bus messages"); if (HasAzureServiceBusFallbackHandler) { if (_fallbackMessageHandler.Value is AzureServiceBusMessageHandlerTemplate template) { if (messageReceiver is null) { Logger.LogWarning("Fallback message handler '{MessageHandlerType}' uses specific Azure Service Bus operations, but is unable to be configured during message routing because the message router didn't receive a Azure Service Bus message receiver; use other '{RouteMessageAsync}' method overload", _fallbackMessageHandler.Value.GetType().Name, nameof(RouteMessageAsync)); } else { var args = new ProcessMessageEventArgs(message, messageReceiver, cancellationToken); template.SetProcessMessageEventArgs(args); } } string fallbackMessageHandlerTypeName = _fallbackMessageHandler.Value.GetType().Name; Logger.LogTrace("Fallback on registered '{FallbackMessageHandlerType}' because none of the message handlers w ere able to process the message", fallbackMessageHandlerTypeName); await _fallbackMessageHandler.Value.ProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); Logger.LogTrace("Fallback message handler '{FallbackMessageHandlerType}' has processed the message", fallbackMessageHandlerTypeName); } }
private async Task <bool> ProcessMessageAsync <TMessageContext>( MessageHandler handler, MessageReceiver messageReceiver, string message, TMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) where TMessageContext : AzureServiceBusMessageContext { bool canProcessMessage = handler.CanProcessMessage(messageContext); var messageType = (Type)handler.GetType().GetProperty("MessageType", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(handler); bool tryDeserializeToMessageFormat = TryDeserializeToMessageFormat(message, messageType, out var result); if (canProcessMessage && tryDeserializeToMessageFormat) { if (result is null) { return(false); } await PreProcessingAsync(handler, messageContext, messageReceiver); await handler.ProcessMessageAsync(result, messageContext, correlationInfo, cancellationToken); return(true); } return(false); }
public async Task CustomMessageHandler_WithContextFilter_UsesFilterDuringSelection() { // Arrange var messageId = Guid.NewGuid().ToString(); var message = new TestMessage { TestProperty = Guid.NewGuid().ToString() }; string messageJson = JsonConvert.SerializeObject(message); var context = new TestMessageContext(messageId, new Dictionary <string, object>()); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); var spyHandler1 = new TestMessageHandler(); var spyHandler2 = new TestMessageHandler(); var collection = new MessageHandlerCollection(new ServiceCollection()); collection.WithMessageHandler <TestMessageHandler, TestMessage, TestMessageContext>( messageContextFilter: ctx => ctx.MessageId == "some other ID", implementationFactory: provider => spyHandler2); collection.WithMessageHandler <TestMessageHandler, TestMessage, TestMessageContext>( messageContextFilter: ctx => ctx.MessageId == messageId, implementationFactory: provider => spyHandler1); collection.WithMessageHandler <TestMessageHandler, TestMessage, TestMessageContext>(); collection.WithMessageHandler <DefaultTestMessageHandler, TestMessage>(); IServiceProvider serviceProvider = collection.Services.BuildServiceProvider(); var router = new TestMessageRouter(serviceProvider, _logger); // Act await router.RouteMessageAsync(messageJson, context, correlationInfo, CancellationToken.None); // Assert Assert.True(spyHandler1.IsProcessed); Assert.False(spyHandler2.IsProcessed); }
public async Task WithMessageRouting_WithIgnoreMissingMembers_GoesThroughDifferentMessageHandler(AdditionalMemberHandling additionalMemberHandling) { // Arrange var services = new ServiceCollection(); var collection = new MessageHandlerCollection(services); var messageHandlerV1 = new OrderV1MessageHandler(); var messageHandlerV2 = new OrderV2MessageHandler(); collection.WithMessageHandler <OrderV1MessageHandler, Order>(provider => messageHandlerV1) .WithMessageHandler <OrderV2MessageHandler, OrderV2>(provider => messageHandlerV2); // Act services.AddMessageRouting(options => options.Deserialization.AdditionalMembers = additionalMemberHandling); // Assert IServiceProvider serviceProvider = services.BuildServiceProvider(); var router = serviceProvider.GetRequiredService <IMessageRouter>(); OrderV2 order = OrderV2Generator.Generate(); var context = new MessageContext("message-id", new Dictionary <string, object>()); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); string json = JsonConvert.SerializeObject(order); await router.RouteMessageAsync(json, context, correlationInfo, CancellationToken.None); Assert.Equal(additionalMemberHandling is AdditionalMemberHandling.Ignore, messageHandlerV1.IsProcessed); Assert.Equal(additionalMemberHandling is AdditionalMemberHandling.Error, messageHandlerV2.IsProcessed); }
public async Task WithServiceBusRouting_IgnoreMissingMembers_ResultsInDifferentMessageHandler(AdditionalMemberHandling additionalMemberHandling) { // Arrange var services = new ServiceCollection(); var collection = new ServiceBusMessageHandlerCollection(services); var messageHandlerV1 = new OrderV1AzureServiceBusMessageHandler(); var messageHandlerV2 = new OrderV2AzureServiceBusMessageHandler(); collection.WithServiceBusMessageHandler <OrderV1AzureServiceBusMessageHandler, Order>(provider => messageHandlerV1) .WithServiceBusMessageHandler <OrderV2AzureServiceBusMessageHandler, OrderV2>(provider => messageHandlerV2); // Act services.AddServiceBusMessageRouting(options => options.Deserialization.AdditionalMembers = additionalMemberHandling); // Assert IServiceProvider serviceProvider = services.BuildServiceProvider(); var router = serviceProvider.GetRequiredService <IAzureServiceBusMessageRouter>(); OrderV2 orderV2 = OrderV2Generator.Generate(); ServiceBusReceivedMessage message = orderV2.AsServiceBusReceivedMessage(); AzureServiceBusMessageContext context = AzureServiceBusMessageContextFactory.Generate(); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); await router.RouteMessageAsync(message, context, correlationInfo, CancellationToken.None); Assert.Equal(additionalMemberHandling is AdditionalMemberHandling.Error, messageHandlerV2.IsProcessed); Assert.Equal(additionalMemberHandling is AdditionalMemberHandling.Ignore, messageHandlerV1.IsProcessed); }
public async Task WithServiceBusMessageRouting_WithMessageHandlerMessageBodyFilter_GoesThroughRegisteredMessageHandlers() { // Arrange var services = new ServiceCollection(); var collection = new ServiceBusMessageHandlerCollection(services); var ignoredHandler = new StubServiceBusMessageHandler <Order>(); var spyHandler = new StubServiceBusMessageHandler <Order>(); collection.WithServiceBusMessageHandler <StubServiceBusMessageHandler <Order>, Order>( messageBodyFilter: body => true, implementationFactory: serviceProvider => spyHandler) .WithServiceBusMessageHandler <StubServiceBusMessageHandler <Order>, Order>( messageBodyFilter: body => false, implementationFactory: serviceProvider => ignoredHandler); // Act services.AddServiceBusMessageRouting(); // Assert IServiceProvider provider = services.BuildServiceProvider(); var router = provider.GetRequiredService <IAzureServiceBusMessageRouter>(); AzureServiceBusMessageContext context = AzureServiceBusMessageContextFactory.Generate(); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); Order order = OrderGenerator.Generate(); ServiceBusReceivedMessage message = order.AsServiceBusReceivedMessage(); await router.RouteMessageAsync(message, context, correlationInfo, CancellationToken.None); Assert.True(spyHandler.IsProcessed); Assert.False(ignoredHandler.IsProcessed); }
public async Task WithMessageRouting_WithMessageHandlerContextFilter_GoesThroughRegisteredMessageHandlers() { // Arrange var services = new ServiceCollection(); var collection = new MessageHandlerCollection(services); var spyHandler = new StubTestMessageHandler <TestMessage, TestMessageContext>(); var ignoredSameTypeHandler = new StubTestMessageHandler <TestMessage, TestMessageContext>(); var ignoredDefaultHandler = new DefaultTestMessageHandler(); var ignoredHandler = new TestMessageHandler(); collection.WithMessageHandler <DefaultTestMessageHandler, TestMessage>(serviceProvider => ignoredDefaultHandler) .WithMessageHandler <StubTestMessageHandler <TestMessage, TestMessageContext>, TestMessage, TestMessageContext>( messageContextFilter: ctx => false, implementationFactory: serviceProvider => ignoredSameTypeHandler) .WithMessageHandler <StubTestMessageHandler <TestMessage, TestMessageContext>, TestMessage, TestMessageContext>(serviceProvider => spyHandler) .WithMessageHandler <TestMessageHandler, TestMessage, TestMessageContext>(serviceProvider => ignoredHandler); // Act services.AddMessageRouting(); // Assert IServiceProvider provider = services.BuildServiceProvider(); var router = provider.GetRequiredService <IMessageRouter>(); var correlationInfo = new MessageCorrelationInfo("operation-id", "transaction-id"); var context = TestMessageContext.Generate(); string json = JsonConvert.SerializeObject(new TestMessage()); await router.RouteMessageAsync(json, context, correlationInfo, CancellationToken.None); Assert.True(spyHandler.IsProcessed); Assert.False(ignoredSameTypeHandler.IsProcessed); Assert.False(ignoredDefaultHandler.IsProcessed); Assert.False(ignoredHandler.IsProcessed); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="azureMessageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public override async Task ProcessMessageAsync( ServiceBusReceivedMessage message, AzureServiceBusMessageContext azureMessageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { if (azureMessageContext.SystemProperties.DeliveryCount <= 1) { Logger.LogTrace("Abandoning message '{MessageId}'...", message.MessageId); await AbandonMessageAsync(message); Logger.LogTrace("Abandoned message '{MessageId}'", message.MessageId); } else { string json = Encoding.UTF8.GetString(message.Body); var order = JsonConvert.DeserializeObject <Order>(json); Logger.LogInformation("Processing order {OrderId} for {OrderAmount} units of {OrderArticle} bought by {CustomerFirstName} {CustomerLastName}", order.Id, order.Amount, order.ArticleNumber, order.Customer.FirstName, order.Customer.LastName); await PublishEventToEventGridAsync(order, correlationInfo.OperationId, correlationInfo); Logger.LogInformation("Order {OrderId} processed", order.Id); } }
/// <summary> /// Handle a new <paramref name="message"/> that was received by routing them through registered <see cref="IAzureServiceBusMessageHandler{TMessage}"/>s /// and optionally through an registered <see cref="IFallbackMessageHandler"/> or <see cref="IAzureServiceBusFallbackMessageHandler"/> if none of the message handlers were able to process the <paramref name="message"/>. /// </summary> /// <param name="messageReceiver"> /// The instance that can receive Azure Service Bus <see cref="ServiceBusReceivedMessage"/>; used within <see cref="IMessageHandler{TMessage,TMessageContext}"/>s with Azure Service Bus specific operations. /// </param> /// <param name="message">The message that was received by the <paramref name="messageReceiver"/>.</param> /// <param name="messageContext">The context in which the <paramref name="message"/> should be processed.</param> /// <param name="correlationInfo">The information concerning correlation of telemetry and processes by using a variety of unique identifiers.</param> /// <param name="cancellationToken">The token to cancel the message processing.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the <paramref name="messageReceiver"/>, <paramref name="message"/>, <paramref name="messageContext"/>, or <paramref name="correlationInfo"/> is <c>null</c>. /// </exception> /// <exception cref="InvalidOperationException">Thrown when no message handlers or none matching message handlers are found to process the message.</exception> protected async Task RouteMessageWithPotentialFallbackAsync( ServiceBusReceiver messageReceiver, ServiceBusReceivedMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Guard.NotNull(message, nameof(message), "Requires an Azure Service Bus message to be processed by the registered message handlers"); Guard.NotNull(messageContext, nameof(messageContext), "Requires an Azure Service Bus message context in which the incoming message can be processed"); Guard.NotNull(correlationInfo, nameof(correlationInfo), "Requires an correlation information to correlate between incoming Azure Service Bus messages"); try { MessageHandler[] messageHandlers = GetRegisteredMessageHandlers().ToArray(); if (messageHandlers.Length <= 0 && !HasFallbackMessageHandler && !HasAzureServiceBusFallbackHandler) { throw new InvalidOperationException( $"Azure Service Bus message pump cannot correctly process the message in the '{nameof(AzureServiceBusMessageContext)}' " + "because no 'IAzureServiceBusMessageHandler<>' was registered in the dependency injection container. " + $"Make sure you call the correct 'WithServiceBusMessageHandler' extension on the {nameof(IServiceCollection)} " + "during the registration of the Azure Service Bus message pump or message router to register a message handler"); } Encoding encoding = messageContext.GetMessageEncodingProperty(Logger); string messageBody = encoding.GetString(message.Body.ToArray()); foreach (MessageHandler messageHandler in messageHandlers) { MessageResult result = await DeserializeMessageForHandlerAsync(messageBody, messageContext, messageHandler); if (result.IsSuccess) { var args = new ProcessMessageEventArgs(message, messageReceiver, cancellationToken); SetServiceBusPropertiesForSpecificOperations(messageHandler, args, messageContext); await messageHandler.ProcessMessageAsync(result.DeserializedMessage, messageContext, correlationInfo, cancellationToken); return; } } if (!HasFallbackMessageHandler && !HasAzureServiceBusFallbackHandler) { throw new InvalidOperationException( $"Message pump cannot correctly process the message in the '{nameof(AzureServiceBusMessageContext)}' " + "because none of the registered 'IAzureServiceBusMessageHandler<,>' implementations in the dependency injection container matches the incoming message type and context; " + $"and no '{nameof(IFallbackMessageHandler)}' or '{nameof(IAzureServiceBusFallbackMessageHandler)}' was registered to fall back to." + $"Make sure you call the correct '.WithServiceBusMessageHandler' extension on the {nameof(IServiceCollection)} during the registration of the message pump or message router to register a message handler"); } await TryFallbackProcessMessageAsync(messageBody, messageContext, correlationInfo, cancellationToken); await TryServiceBusFallbackMessageAsync(messageReceiver, message, messageContext, correlationInfo, cancellationToken); } catch (Exception exception) { Logger.LogCritical(exception, "Unable to process message with ID '{MessageId}'", message.MessageId); throw; } }
/// <summary> /// Process the given <paramref name="message"/> in the current <see cref="IMessageHandler{TMessage,TMessageContext}"/> representation. /// </summary> /// <param name="message">The parsed message to be processed by the <see cref="IMessageHandler{TMessage,TMessageContext}"/>.</param> /// <param name="messageContext">The context providing more information concerning the processing.</param> /// <param name="correlationInfo"> /// The information concerning correlation of telemetry and processes by using a variety of unique /// identifiers. /// </param> /// <param name="cancellationToken">The cancellation token.</param> public async Task ProcessMessageAsync( TMessage message, TMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { await Service.ProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public Task ProcessMessageAsync( string message, MessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { return(Task.CompletedTask); }
/// <summary>Process a new message that was received</summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public async Task ProcessMessageAsync( Order message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { throw new NotImplementedException(); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public Task ProcessMessageAsync( ServiceBusReceivedMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { return(Task.CompletedTask); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public Task ProcessMessageAsync( TestMessage message, MessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { IsProcessed = true; return(Task.CompletedTask); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public Task ProcessMessageAsync( Order message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { throw new InvalidOperationException( "Sabotage the message processing with an unhandled exception"); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public Task ProcessMessageAsync( OrderV2 message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { IsProcessed = true; return(Task.CompletedTask); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public override async Task ProcessMessageAsync( Order message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { await _orderMessageHandler.ProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); await CompleteMessageAsync(); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">The Azure Service Bus Message message that was received</param> /// <param name="messageContext">The context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// The information concerning correlation of telemetry and processes by using a variety of unique /// identifiers. /// </param> /// <param name="cancellationToken">The cancellation token to cancel the processing.</param> public override async Task ProcessMessageAsync( ServiceBusReceivedMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { await _fallbackMessageHandler.ProcessMessageAsync(message, messageContext, correlationInfo, cancellationToken); await CompleteAsync(message); }
/// <summary> /// Gets the correlation information for a given message. /// </summary> /// <param name="message">The received message.</param> public static MessageCorrelationInfo GetCorrelationInfo(this Message message) { Guard.NotNull(message, nameof(message)); string transactionId = GetTransactionId(message); string operationId = DetermineOperationId(message.CorrelationId); var messageCorrelationInfo = new MessageCorrelationInfo(operationId, transactionId); return(messageCorrelationInfo); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public override async Task ProcessMessageAsync( Order message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Logger.LogTrace("Dead letter message '{OrderId}'...", message.Id); await DeadLetterMessageAsync(); Logger.LogInformation("Message '{OrderId}' is dead lettered", message.Id); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="batch">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public async Task ProcessMessageAsync( OrderBatch batch, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { foreach (Order order in batch.Orders) { await _messageHandler.ProcessMessageAsync(order, messageContext, correlationInfo, cancellationToken); } }
/// <summary>Process a new message that was received</summary> /// <param name="message">Message that was received</param> /// <param name="messageContext">Context providing more information concerning the processing</param> /// <param name="correlationInfo"> /// Information concerning correlation of telemetry and processes by using a variety of unique /// identifiers /// </param> /// <param name="cancellationToken">Cancellation token</param> public async Task ProcessMessageAsync( EmptyMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { _logger.LogTrace("Processing message {message}...", message); // Process message. _logger.LogInformation("Message {message} processed!", message); }
/// <summary> /// Gets the correlation information for a given <paramref name="message"/>. /// </summary> /// <param name="message">The received message.</param> /// <param name="transactionIdPropertyName">Name of the property to determine the transaction id.</param> /// <returns> /// The correlation information wrapped inside an <see cref="MessageCorrelationInfo"/>, /// containing the operation and transaction ID from the received <paramref name="message"/>; /// otherwise both will be generated GUID's. /// </returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="message"/>.</exception> /// <exception cref="ArgumentException">Thrown when the <paramref name="transactionIdPropertyName"/> is blank.</exception> public static MessageCorrelationInfo GetCorrelationInfo(this ServiceBusReceivedMessage message, string transactionIdPropertyName) { Guard.NotNull(message, nameof(message), "Requires an received Azure Service Bus message to retrieve the correlation information"); Guard.NotNullOrWhitespace(transactionIdPropertyName, nameof(transactionIdPropertyName), "Requires a non-blank property name to retrieve the correlation transaction ID from the received Azure Service Bus message"); string transactionId = DetermineTransactionId(message, transactionIdPropertyName); string operationId = DetermineOperationId(message.CorrelationId); var messageCorrelationInfo = new MessageCorrelationInfo(operationId, transactionId); return(messageCorrelationInfo); }