/// <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); }
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)); }
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)); }