/// <summary> /// Asynchronously publishes the specified message to a bus. /// </summary> /// <typeparam name="TMessage"> /// The type of the message to publish. /// </typeparam> /// <param name="message"> /// The message to publish. /// </param> /// <param name="entityType"> /// The targeted entity type. /// </param> /// <param name="controlToken"> /// A token that ensures thread safety for the operation. /// </param> /// <returns> /// A task representing the asynchronous operation. /// </returns> protected sealed override async Task PublishAsync <TMessage>(TMessage message, MessagingEntityType entityType, ConcurrencyControlToken controlToken) { var messageType = typeof(TMessage); var serializedMessage = SerializeMessage(message); var azureServiceBusMessage = AzureServiceBusClientManager.CreateAzureServiceBusMessage(serializedMessage, messageType, MessageSerializationFormat, message.Identifier, message.CorrelationIdentifier); var sendClient = ClientManager.GetSendClient <TMessage>(entityType); await sendClient.SendAsync(azureServiceBusMessage).ConfigureAwait(false); }
/// <summary> /// Registers the specified message handler with the bus. /// </summary> /// <typeparam name="TRequestMessage"> /// The type of the request message. /// </typeparam> /// <typeparam name="TResponseMessage"> /// The type of the response message. /// </typeparam> /// <param name="requestMessageHandler"> /// A function that handles a request message. /// </param> /// <param name="requestMessageEntityType"> /// The entity type that is used for publishing and subscribing to request messages. /// </param> /// <param name="responseMessageEntityType"> /// The entity type that is used for publishing and subscribing to response messages. /// </param> /// <param name="controlToken"> /// A token that ensures thread safety for the operation. /// </param> protected sealed override void RegisterHandler <TRequestMessage, TResponseMessage>(Func <TRequestMessage, TResponseMessage> requestMessageHandler, MessagingEntityType requestMessageEntityType, MessagingEntityType responseMessageEntityType, ConcurrencyControlToken controlToken) { var responseMessageType = typeof(TResponseMessage); var requestReceiveClient = ClientManager.GetReceiveClient <TRequestMessage>(requestMessageEntityType); var responseSendClient = ClientManager.GetSendClient <TResponseMessage>(responseMessageEntityType); var messageHandlerFunction = new Func <AzureServiceBusMessage, CancellationToken, Task>(async(azureServiceBusRequestMessage, cancellationToken) => { var lockToken = azureServiceBusRequestMessage.SystemProperties?.LockToken; if (lockToken is null) { throw new MessageSubscriptionException("The lock token is invalid."); } var deserializedRequestMessage = DeserializeMessage <TRequestMessage>(azureServiceBusRequestMessage.Body); var requestMessageIdentifier = deserializedRequestMessage.Identifier.ToSerializedString(); if (requestReceiveClient.IsClosedOrClosing) { throw new MessageSubscriptionException("The message cannot be processed because the receive client is unavailable."); } try { cancellationToken.ThrowIfCancellationRequested(); var responseMessage = requestMessageHandler(deserializedRequestMessage); var serializedResponseMessage = SerializeMessage(responseMessage); var azureServiceBusResponseMessage = AzureServiceBusClientManager.CreateAzureServiceBusMessage(serializedResponseMessage, responseMessageType, MessageSerializationFormat, responseMessage.Identifier, responseMessage.CorrelationIdentifier, deserializedRequestMessage.Identifier); await responseSendClient.SendAsync(azureServiceBusResponseMessage).ContinueWith(async(task) => { switch (task.Status) { case TaskStatus.RanToCompletion: await requestReceiveClient.CompleteAsync(lockToken).ConfigureAwait(false); break; default: await requestReceiveClient.AbandonAsync(lockToken).ConfigureAwait(false); break; } }).ConfigureAwait(false); } catch { await requestReceiveClient.AbandonAsync(lockToken).ConfigureAwait(false); throw; } }); requestReceiveClient.RegisterMessageHandler(messageHandlerFunction, ClientManager.ReceiverOptionsForRequestMessages); }
/// <summary> /// Asynchronously publishes the specified request message to a bus and waits for the correlated response message. /// </summary> /// <typeparam name="TRequestMessage"> /// The type of the request message. /// </typeparam> /// <typeparam name="TResponseMessage"> /// The type of the response message. /// </typeparam> /// <param name="requestMessage"> /// The request message to publish. /// </param> /// <param name="controlToken"> /// A token that ensures thread safety for the operation. /// </param> /// <returns> /// A task representing the asynchronous operation and containing the correlated response message. /// </returns> protected sealed override async Task <TResponseMessage> RequestAsync <TRequestMessage, TResponseMessage>(TRequestMessage requestMessage, ConcurrencyControlToken controlToken) { var requestMessageType = typeof(TRequestMessage); var serializedRequestMessage = SerializeMessage(requestMessage); var azureServiceBusRequestMessage = AzureServiceBusClientManager.CreateAzureServiceBusMessage(serializedRequestMessage, requestMessageType, MessageSerializationFormat, requestMessage.Identifier, requestMessage.CorrelationIdentifier); var requestClient = ClientManager.GetRequestClient <TRequestMessage, TResponseMessage>(); ClientManager.AddOutstandingRequest(requestMessage.Identifier); using (var sendTask = requestClient.SendAsync(azureServiceBusRequestMessage)) { using (var waitForResponseTask = ClientManager.WaitForResponseAsync(requestMessage.Identifier)) { await Task.WhenAll(sendTask, waitForResponseTask); return(DeserializeMessage <TResponseMessage>(waitForResponseTask.Result.Body)); } } }