protected virtual async Task ExecuteMessageHandlerAsync( EventArgs messageEventArgs, ReceivedItemHandlerAsyncDelegate receivedItemHandlerAsyncDelegateFunc, bool automaticFinalizationEnabled = true ) { messageEventArgs.AssertNotNull(nameof(messageEventArgs)); receivedItemHandlerAsyncDelegateFunc.AssertNotNull(nameof(receivedItemHandlerAsyncDelegateFunc)); AzureServiceBusReceivedItem <TUniqueIdentifier, TPayload> azureServiceBusReceivedItem = null; //FIRST attempt to convert the Message into an AzureServiceBus Received Item.... try { //Initialize the MessageHandler facade for processing the Azure Service Bus message... azureServiceBusReceivedItem = await CreateReceivedItemAsync( messageEventArgs, //Force Dead-lettering if there is any issue with initialization! true ).AssertNotNull(nameof(azureServiceBusReceivedItem)); } catch (Exception exc) { var messageException = new Exception("The message could not be correctly initialized due to unexpected exception." + " It must be Dead lettered to prevent blocking of the Service Bus as it will never be" + " processed successfully.", exc); this.Options.ErrorHandlerCallback?.Invoke(messageException); } //IF the Received Item is successfully initialized then process it! if (azureServiceBusReceivedItem != null) { try { //Execute the delegate to handle/process the published item... await receivedItemHandlerAsyncDelegateFunc(azureServiceBusReceivedItem).ConfigureAwait(false); //If necessary, we need to Finalize the item with Azure Service Bus (Complete/Abandon) based on the Status returned on the item! if (automaticFinalizationEnabled && !azureServiceBusReceivedItem.IsStatusFinalized) { await azureServiceBusReceivedItem.SendFinalizedStatusToAzureServiceBusAsync().ConfigureAwait(false); } } catch (Exception exc) { this.Options.ErrorHandlerCallback?.Invoke(exc); //Always attempt to Reject/Abandon the message if any unhandled exceptions are thrown... if (!azureServiceBusReceivedItem.IsStatusFinalized) { //Finalize the status as set by the Delegate function if it's not already Finalized! //NOTE: We ALWAYS do this even if autoMessageFinalizationEnabled is false to prevent BLOCKING and risk of Infinite Loops... await azureServiceBusReceivedItem.SendFinalizedStatusToAzureServiceBusAsync().ConfigureAwait(false); } } } }
protected virtual async Task <AzureServiceBusReceivedItem <TUniqueIdentifier, TPayload> > CreateReceivedItemAsync( EventArgs baseMessageEventArgs, bool deadLetterOnFailureToInitialize = false ) { AzureServiceBusReceivedItem <TUniqueIdentifier, TPayload> azureServiceBusReceivedItem = null; var initializationErrorMessage = $"Unable to initialize {nameof(SqlTransactionalOutbox)} Received Item [{nameof(AzureServiceBusReceivedItem<TUniqueIdentifier, TPayload>)}]"; switch (baseMessageEventArgs) { case ProcessMessageEventArgs messageEventArgs: try { azureServiceBusReceivedItem = new AzureServiceBusReceivedItem <TUniqueIdentifier, TPayload>(messageEventArgs, this.OutboxItemFactory); } catch (Exception exc) { if (deadLetterOnFailureToInitialize) { await messageEventArgs.DeadLetterMessageAsync(messageEventArgs.Message, initializationErrorMessage, exc.GetMessagesRecursively()); } throw; } break; case ProcessSessionMessageEventArgs sessionMessageEventArgs: try { azureServiceBusReceivedItem = new AzureServiceBusReceivedItem <TUniqueIdentifier, TPayload>(sessionMessageEventArgs, this.OutboxItemFactory); } catch (Exception exc) { if (deadLetterOnFailureToInitialize) { await sessionMessageEventArgs.DeadLetterMessageAsync(sessionMessageEventArgs.Message, initializationErrorMessage, exc.GetMessagesRecursively()); } throw; } break; } return(azureServiceBusReceivedItem); }