public async Task MessageReceived(Message message, IQueuedMessageContext context, CancellationToken cancellationToken = default(CancellationToken)) { var messageContext = new BusMessageContext(_bus, context.Headers, context.SenderPrincipal); await MessageHandler.HandleMessage(_messageNamingService, _serializationService, _messageHandlers, message, messageContext, cancellationToken); if (messageContext.MessageAcknowledged) { await context.Acknowledge(); } }
public ISentMessage CreateSentMessage(Message message) { CheckDisposed(); var messageId = message.Headers.MessageId; var replyStreamExpiration = DateTime.UtcNow.Add(_replyTimeout); var newReplyStream = new ReplyStream(); var replyStream = (ReplyStream) _cache.AddOrGetExisting(messageId, newReplyStream, replyStreamExpiration); // ReSharper disable once ConvertIfStatementToNullCoalescingExpression if (replyStream == null) { // MemoryCache.AddOrGetExisting returns null if the key does not // already exist, so use the one we just created. See: // http://msdn.microsoft.com/en-us/library/dd988741%28v=vs.110%29.aspx replyStream = newReplyStream; } return new SentMessageWithCachedReplies(messageId, replyStream); }
public static async Task HandleMessage(IMessageNamingService messageNamingService, ISerializationService serializationService, IEnumerable<IMessageHandler> messageHandlers, Message message, IMessageContext messageContext, CancellationToken cancellationToken = default(CancellationToken)) { if (message.Headers.Expires < DateTime.UtcNow) { Log.WarnFormat("Discarding expired \"{0}\" message (ID {1}, expired {2})", message.Headers.MessageName, message.Headers.MessageId, message.Headers.Expires); messageContext.Acknowledge(); return; } var messageType = messageNamingService.GetTypeForName(message.Headers.MessageName); var serializer = serializationService.GetSerializer(message.Headers.ContentType); var messageContent = serializer.Deserialize(message.Content, messageType); var handlingTasks = messageHandlers.Select( handler => handler.HandleMessage(messageContent, messageContext, cancellationToken)); await Task.WhenAll(handlingTasks); }
public async Task PublishMessage(Message message, TopicName topicName, CancellationToken cancellationToken) { await Task.Run(() => _accept(message, Thread.CurrentPrincipal), cancellationToken); }
public async Task SendMessage(Message message, IEndpointCredentials credentials = null, CancellationToken cancellationToken = new CancellationToken()) { await Task.Run(() => _accept(message, Thread.CurrentPrincipal), cancellationToken); }
private async Task NotifyReplyReceived(Message message) { // TODO: Handle special "last reply" message. Presently we only support a single reply. // This will probably be a special function of the ITransportService and will likely // be, for example, an empty POST to {baseUri}/message/{messageId}?lastReply=true, which // will trigger the OnComplete event in the IObservable reply stream. However, we need // to put some thought into potential issues around the sequence and timing of replies // vs. the final lastReply POST to ensure that all replies are processed before the // OnComplete event is triggered. One possibility is a reply sequence number header // and an indication of the total number of replies in the lastReply POST. If the // number of replies received is less than the number expected, then the OnComplete // event can be deferred. var relatedToMessageId = message.Headers.RelatedTo; var messageType = _messageNamingService.GetTypeForName(message.Headers.MessageName); var serializer = _serializationService.GetSerializer(message.Headers.ContentType); var messageContent = serializer.Deserialize(message.Content, messageType); await _replyHub.ReplyReceived(messageContent, relatedToMessageId); await _replyHub.NotifyLastReplyReceived(relatedToMessageId); }
private async Task HandleMessageImmediately(Message message, SenderPrincipal senderPrincipal, bool isReply) { var messageContext = new BusMessageContext(this, message.Headers, senderPrincipal); var handlers = _handlingRules .Where(r => r.Specification.IsSatisfiedBy(message)) .Select(rule => rule.MessageHandler) .ToList(); if (!handlers.Any() && isReply) { // TODO: Figure out what to do here. return; } await MessageHandler.HandleMessage(_messageNamingService, _serializationService, handlers, message, messageContext, _cancellationTokenSource.Token); if (!messageContext.MessageAcknowledged) { throw new MessageNotAcknowledgedException(); } }
/// <summary> /// Called by the host when a new message arrives to handle the message /// </summary> /// <param name="message">The new message</param> /// <param name="principal">The sender principal</param> /// <returns>Returns a task that completes when message handling is complete</returns> public async Task HandleMessage(Message message, IPrincipal principal) { if (_messageJournalingService != null) { await _messageJournalingService.MessageReceived(message); } // Make sure that the principal is serializable before enqueuing var senderPrincipal = principal as SenderPrincipal; if (senderPrincipal == null && principal != null) { senderPrincipal = new SenderPrincipal(principal); } var tasks = new List<Task>(); var relatedToMessageId = message.Headers.RelatedTo; var isReply = relatedToMessageId != default(MessageId); if (isReply) { tasks.Add(NotifyReplyReceived(message)); } var importance = message.Headers.Importance; if (importance.RequiresQueueing) { // Message expiration handled in MessageHandlingListener tasks.AddRange(_handlingRules .Where(r => r.Specification.IsSatisfiedBy(message)) .Select(rule => rule.QueueName) .Distinct() .Select(q => _messageQueueingService.EnqueueMessage(q, message, senderPrincipal))); } else { tasks.Add(HandleMessageImmediately(message, senderPrincipal, isReply)); } await Task.WhenAll(tasks); }
private IEnumerable<KeyValuePair<EndpointName, IEndpoint>> GetEndpointsForMessage(Message message) { return _sendRules .Where(rule => rule.Specification.IsSatisfiedBy(message)) .SelectMany(rule => rule.Endpoints) .Join(_endpoints, endpointName => endpointName, endpointEntry => endpointEntry.Key, (_, endpointEntry) => endpointEntry); }
/// <summary> /// Sends a <paramref name="content" /> to default configured endpoints. /// </summary> /// <param name="content">The content to send.</param> /// <param name="options">Optional settings that influence how the message is sent.</param> /// <param name="cancellationToken">An optional cancellation token</param> public async Task<ISentMessage> Send(object content, SendOptions options = default(SendOptions), CancellationToken cancellationToken = default(CancellationToken)) { CheckDisposed(); if (content == null) throw new ArgumentNullException("content"); var prototypicalMessage = BuildMessage(content, options: options); var endpoints = GetEndpointsForMessage(prototypicalMessage); var transportTasks = new List<Task>(); // Create the sent message before transporting it in order to ensure that the // reply stream is cached before any replies arrive. var sentMessage = _replyHub.CreateSentMessage(prototypicalMessage); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var kvp in endpoints) { var endpointName = kvp.Key; var endpoint = kvp.Value; var credentials = endpoint.Credentials; var perEndpointHeaders = new MessageHeaders(prototypicalMessage.Headers) { Destination = endpoint.Address }; Log.DebugFormat("Sending message ID {0} to endpoint \"{1}\" ({2})...", prototypicalMessage.Headers.MessageId, endpointName, endpoint.Address); var addressedMessage = new Message(perEndpointHeaders, prototypicalMessage.Content); transportTasks.Add(_transportService.SendMessage(addressedMessage, credentials, cancellationToken)); } await Task.WhenAll(transportTasks); return sentMessage; }