/// <summary>
        /// Dispatches a message to the specified consumer.  The implementation
        /// normalizes the calling for synchronous and asynchronous message handlers.
        /// This allows the method handler to be re-factored to one or the other
        /// without having to change any of the calling code.  This also decouples
        /// the publisher from the consumer.  The publisher should not be concerned
        /// or determine how the message is handled.
        /// </summary>
        /// <param name="message">The message to be dispatched.</param>
        /// <param name="consumer">Instance of the consumer to have message dispatched.</param>
        /// <param name="cancellationToken">The optional cancellation token passed to the message handler.</param>
        /// <returns>The response as a future result.</returns>
        public async Task <object> Dispatch(IMessage message, IMessageConsumer consumer, CancellationToken cancellationToken)
        {
            Check.NotNull(message, nameof(message));
            Check.NotNull(consumer, nameof(consumer));

            var futureResult = new TaskCompletionSource <object>();

            try
            {
                if (IsAsync)
                {
                    Task asyncResult = null;

                    var invokeParams = new List <object> {
                        consumer, message
                    };
                    if (IsCancellable)
                    {
                        invokeParams.Add(cancellationToken);
                    }

                    asyncResult = (Task)Invoker.DynamicInvoke(invokeParams.ToArray());
                    await asyncResult;

                    object result = ProcessResult(message, asyncResult);
                    futureResult.SetResult(result);
                }
                else
                {
                    object syncResult = Invoker.DynamicInvoke(consumer, message);
                    object result     = ProcessResult(message, syncResult);
                    futureResult.SetResult(result);
                }
            }
            catch (Exception ex)
            {
                var invokeEx = ex as TargetInvocationException;
                var sourceEx = ex;

                if (invokeEx != null)
                {
                    sourceEx = invokeEx.InnerException;
                }

                var dispatchEx = new MessageDispatchException("Exception Dispatching Message.",
                                                              this,
                                                              sourceEx);

                futureResult.SetException(dispatchEx);
            }

            return(await futureResult.Task);
        }
Beispiel #2
0
        private static Task ReplyWithException(ConsumeContext context, Exception ex)
        {
            if (!(ex is MessageDispatchException dispatchEx))
            {
                dispatchEx = new MessageDispatchException(ex.Message);
            }

            var replyMessageProps = GetReplyMessageProps(context);

            replyMessageProps.SetRpcReplyException(true);

            return(PublishConsumerReply(context, replyMessageProps, dispatchEx));
        }
Beispiel #3
0
        private void PublishConsumerExceptionReply(Exception ex, IBasicProperties requestProps)
        {
            var dispatchEx = ex as MessageDispatchException;

            if (ex == null)
            {
                dispatchEx = new MessageDispatchException("Error dispatching RPC consumer", ex);
            }

            // Serialize the exception and make it the body of the message.  Indicate to the
            // publisher that the message body is the exception by setting message header.
            byte[] replyBody = _serializationMgr.Serialize(dispatchEx, requestProps.ContentType);
            var    headers   = new Dictionary <string, object> {
                { RpcClient.RPC_HEADER_EXCEPTION_INDICATOR, true }
            };

            PublishResponseToConsumer(replyBody, requestProps, headers);
        }
        /// <summary>
        /// Dispatches a message to the specified consumer.  The implementation normalizes the
        /// calling for synchronous and asynchronous message handlers.  This allows the method
        /// handler to be re-factored to one or the other without having to change any of the
        /// calling code.  This also decouples the publisher from the consumer.  The publisher
        /// should not be concerned of how the message is handled.
        /// </summary>
        /// <param name="message">The message to be dispatched.</param>
        /// <param name="consumer">Instance of the consumer to have message dispatched.</param>
        /// <param name="cancellationToken">The cancellation token passed to the message handler.</param>
        /// <returns>The response as a future task result.</returns>
        public async Task <object> Dispatch(IMessage message, IMessageConsumer consumer, CancellationToken cancellationToken)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (consumer == null)
            {
                throw new ArgumentNullException(nameof(consumer));
            }
            if (cancellationToken == null)
            {
                throw new ArgumentNullException(nameof(cancellationToken));
            }

            var taskSource = new TaskCompletionSource <object>();

            try
            {
                if (IsAsync)
                {
                    var invokeParams = new List <object> {
                        consumer, message
                    };
                    if (IsCancellable)
                    {
                        invokeParams.Add(cancellationToken);
                    }

                    var asyncResult = (Task)Invoker.DynamicInvoke(invokeParams.ToArray());
                    await asyncResult.ConfigureAwait(false);

                    object result = ProcessResult(message, asyncResult);
                    taskSource.SetResult(result);
                }
                else
                {
                    object syncResult = Invoker.DynamicInvoke(consumer, message);
                    object result     = ProcessResult(message, syncResult);
                    taskSource.SetResult(result);
                }
            }
            catch (Exception ex)
            {
                var invokeEx = ex as TargetInvocationException;
                var sourceEx = ex;

                if (invokeEx != null)
                {
                    sourceEx = invokeEx.InnerException;
                }

                var dispatchEx = new MessageDispatchException("Exception Dispatching Message.",
                                                              this,
                                                              sourceEx);

                taskSource.SetException(dispatchEx);
            }

            return(await taskSource.Task.ConfigureAwait(false));
        }