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); }
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); }
/// <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); } }
/// <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); } }
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); }
/// <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 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(); }
protected override async Task ProcessMessageAsync(Order orderMessage, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Logger.LogInformation("Processing order {OrderId} for {OrderAmount} units of {OrderArticle} bought by {CustomerFirstName} {CustomerLastName}", orderMessage.Id, orderMessage.Amount, orderMessage.ArticleNumber, orderMessage.Customer.FirstName, orderMessage.Customer.LastName); await PublishEventToEventGridAsync(orderMessage, correlationInfo.OperationId, correlationInfo); Logger.LogInformation("Order {OrderId} processed", orderMessage.Id); }
/// <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( 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 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 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> /// 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); }
protected virtual async Task PreProcessingAsync( MessageHandler handler, AzureServiceBusMessageContext messageContext, MessageReceiver messageReceiver) { if (handler.Service is AzureServiceBusMessageHandlerTemplate template) { template.GetType().GetMethod("SetMessageReceiver", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(template, new [] { messageReceiver }); template.GetType().GetMethod("SetLockToken", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(template, new [] { messageContext.SystemProperties.LockToken }); } }
/// <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); }
public async Task Run( [ServiceBusTrigger("myqueue", Connection = "")] string myQueueItem, Microsoft.Azure.ServiceBus.Message message, MessageReceiver messageReceiver, ILogger log) { log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}"); var context = new AzureServiceBusMessageContext(message.MessageId, message.SystemProperties, message.UserProperties); MessageCorrelationInfo correlation = message.GetCorrelationInfo(); await _router.ProcessMessageAsync(messageReceiver, message, context, correlation, CancellationToken.None); }
public async Task WithServiceBusRouting_WithMessageHandlerCanHandleAllFiltersAtOnce_AndStillFindsTheRightMessageHandler() { // Arrange var services = new ServiceCollection(); var collection = new ServiceBusMessageHandlerCollection(services); var ignoredHandler1 = new StubServiceBusMessageHandler <TestMessage>(); var ignoredHandler2 = new StubServiceBusMessageHandler <TestMessage>(); var ignoredHandler3 = new StubServiceBusMessageHandler <Order>(); var spyHandler = new StubServiceBusMessageHandler <Order>(); AzureServiceBusMessageContext context = AzureServiceBusMessageContextFactory.Generate(); var expectedMessage = new TestMessage { TestProperty = "Some value" }; string expectedBody = JsonConvert.SerializeObject(expectedMessage); var serializer = new TestMessageBodySerializer(expectedBody, OrderGenerator.Generate()); collection .WithServiceBusMessageHandler <StubServiceBusMessageHandler <Order>, Order>( messageContextFilter: ctx => ctx != null, messageBodyFilter: body => body != null, messageBodySerializer: new TestMessageBodySerializer(expectedBody, new Customer()), implementationFactory: serviceProvider => ignoredHandler3) .WithServiceBusMessageHandler <StubServiceBusMessageHandler <TestMessage>, TestMessage>( messageBodyFilter: body => body is null, implementationFactory: serviceProvider => ignoredHandler2) .WithServiceBusMessageHandler <StubServiceBusMessageHandler <Order>, Order>( messageBodySerializer: serializer, messageBodyFilter: body => body.Customer != null, messageContextFilter: ctx => ctx.MessageId.StartsWith("message-id"), implementationFactory: serviceProvider => spyHandler) .WithServiceBusMessageHandler <StubServiceBusMessageHandler <TestMessage>, TestMessage>() .WithServiceBusMessageHandler <StubServiceBusMessageHandler <TestMessage>, TestMessage>( implementationFactory: serviceProvider => ignoredHandler1); // Act services.AddServiceBusMessageRouting(); // Assert IServiceProvider provider = services.BuildServiceProvider(); var router = provider.GetRequiredService <IAzureServiceBusMessageRouter>(); 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(ignoredHandler1.IsProcessed); Assert.False(ignoredHandler2.IsProcessed); Assert.False(ignoredHandler3.IsProcessed); }
/// <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) { _logger.LogInformation( "Processing order {OrderId} for {OrderAmount} units of {OrderArticle}", message.Id, message.Amount, message.ArticleNumber); await PublishEventToEventGridAsync(message, correlationInfo.OperationId, correlationInfo); _logger.LogInformation("Order {OrderId} processed", message.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> public async Task RouteMessageAsync( ServiceBusReceiver messageReceiver, ServiceBusReceivedMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Guard.NotNull(messageReceiver, nameof(messageReceiver), "Requires an Azure Service Bus message receiver while processing the message, so message handlers can call Azure Service Bus specific operations"); 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"); await RouteMessageWithPotentialFallbackAsync(messageReceiver, message, messageContext, correlationInfo, cancellationToken); }
/// <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 async Task ProcessMessageAsync( ServiceBusReceivedMessage message, AzureServiceBusMessageContext azureMessageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { string messageBody = Encoding.UTF8.GetString(message.Body); var order = JsonConvert.DeserializeObject <Order>(messageBody); _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> /// 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( CloudEvent message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Guard.NotNull(message, nameof(message), "Cannot invalidate Azure KeyVault secret from a 'null' CloudEvent"); var secretNewVersionCreated = message.GetPayload <SecretNewVersionCreated>(); if (secretNewVersionCreated is null) { throw new CloudException( "Azure Key Vault job cannot map Event Grid event to CloudEvent because the event data isn't recognized as a 'SecretNewVersionCreated' schema"); } await _cachedSecretProvider.InvalidateSecretAsync(secretNewVersionCreated.ObjectName); _logger.LogInformation("Invalidated Azure Key Vault '{SecretName}' secret in vault '{VaultName}'", secretNewVersionCreated.ObjectName, secretNewVersionCreated.VaultName); }
/// <summary> /// Generates a valid <see cref="AzureServiceBusMessageContext"/> instance. /// </summary> public static AzureServiceBusMessageContext Generate() { var amqp = new AmqpAnnotatedMessage(new AmqpMessageBody(new ReadOnlyMemory <byte> [0])); amqp.Header.DeliveryCount = BogusGenerator.Random.UInt(); var message = (ServiceBusReceivedMessage)Activator.CreateInstance(typeof(ServiceBusReceivedMessage), BindingFlags.NonPublic | BindingFlags.Instance, args: new object[] { amqp }, binder: null, culture: null, activationAttributes: null); AzureServiceBusSystemProperties systemProperties = message.GetSystemProperties(); var context = new AzureServiceBusMessageContext( $"message-id-{Guid.NewGuid()}", $"job-id-{Guid.NewGuid()}", systemProperties, new Dictionary <string, object>()); return(context); }
/// <summary> /// Process a new message that was received /// </summary> /// <param name="order">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( Order order, AzureServiceBusMessageContext azureMessageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { if (++_deliveryCount <= 1) { Logger.LogTrace("Abandoning message '{OrderId}'...", order.Id); await AbandonMessageAsync(); Logger.LogTrace("Abandoned message '{OrderId}'", order.Id); } else { 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> /// 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> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="message"/> is <c>null</c>.</exception> /// <exception cref="CloudException">Thrown when the <paramref name="message"/> doesn't represent an <see cref="SecretNewVersionCreated"/> event.</exception> public async Task ProcessMessageAsync( CloudEvent message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken) { Guard.NotNull(message, nameof(message), "Cannot invalidate Azure KeyVault secret from a 'null' CloudEvent"); _logger.LogTrace("Receiving new Azure Key Vault notification..."); var secretNewVersionCreated = message.GetPayload <SecretNewVersionCreated>(); if (secretNewVersionCreated is null) { _logger.LogWarning("Azure Key Vault job cannot map Event Grid event to CloudEvent because the event data isn't recognized as a 'SecretNewVersionCreated' schema"); } else { if (_targetConnectionStringKey == secretNewVersionCreated.ObjectName) { _logger.LogTrace("Received Azure Key vault 'Secret New Version Created' event, restarting target message pump '{JobId}' on entity path '{EntityPath}' in '{Namespace}'", _messagePump.JobId, _messagePump.EntityPath, _messagePump.Namespace); await _messagePump.RestartAsync(); _logger.LogEvent("Message pump restarted", new Dictionary <string, object> { ["JobId"] = _messagePump.JobId, ["EntityPath"] = _messagePump.EntityPath, ["Namespace"] = _messagePump.Namespace }); } else { _logger.LogTrace("Received Azure Key Vault 'Secret New Version Created' event for another secret, ignoring."); } } }
/// <summary> /// Sets the Azure Service Bus properties on registered <see cref="IAzureServiceBusMessageHandler{TMessage}"/>s /// that implements the <see cref="AzureServiceBusMessageHandler{TMessage}"/> for calling specific Service Bus operations during the message processing. /// </summary> /// <param name="messageHandler">The message handler on which the Service Bus properties should be set.</param> /// <param name="eventArgs">The event args of the incoming Service Bus message.</param> /// <param name="messageContext">The context in which the received Service Bus message is processed.</param> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="messageHandler"/> or <paramref name="messageContext"/> is <c>null</c>.</exception> protected void SetServiceBusPropertiesForSpecificOperations( MessageHandler messageHandler, ProcessMessageEventArgs eventArgs, AzureServiceBusMessageContext messageContext) { Guard.NotNull(messageHandler, nameof(messageHandler), "Requires an Azure Service Bus message handler to set the specific Service Bus properties"); Guard.NotNull(messageContext, nameof(messageContext), "Requires an Azure Service Bus message context in which the incoming message can be processed"); object messageHandlerInstance = messageHandler.GetMessageHandlerInstance(); Type messageHandlerType = messageHandlerInstance.GetType(); if (messageHandlerInstance is AzureServiceBusMessageHandlerTemplate template) { if (eventArgs is null) { Logger.LogWarning("Message handler '{MessageHandlerType}' uses specific Azure Service Bus operations, but is not able to be configured during message routing because the message router didn't receive a Azure Service Bus message receiver; use other '{RouteMessageOverload}' method overload", messageHandlerType.Name, nameof(RouteMessageAsync)); } else { template.SetProcessMessageEventArgs(eventArgs); } } }
/// <summary> /// Process a new Azure Service Bus 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 token to cancel the processing.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the <paramref name="message"/>, the <paramref name="messageContext"/>, or the <paramref name="correlationInfo"/> is <c>null</c>. /// </exception> public abstract Task ProcessMessageAsync( TMessage message, AzureServiceBusMessageContext messageContext, MessageCorrelationInfo correlationInfo, CancellationToken cancellationToken);