private static void SendResponse(Task previous, ServerTransport transport, ServerResponseContext context, Tuple <RpcServer, long, int?, string> sessionState) { if (context == null) { if (previous.IsFaulted) { try { previous.Exception.Handle(inner => inner is OperationCanceledException); } catch (AggregateException exception) { InvocationHelper.HandleInvocationException( sessionState.Item2, MessageType.Notification, null, sessionState.Item4, exception, sessionState.Item1.Configuration.IsDebugMode ); } } previous.Dispose(); return; } switch (previous.Status) { case TaskStatus.Canceled: { context.Serialize <object>(null, new RpcErrorMessage(RpcError.TimeoutError, "Server task exceeds execution timeout.", null), null); break; } case TaskStatus.Faulted: { context.Serialize <object>(null, new RpcErrorMessage(RpcError.RemoteRuntimeError, "Dispatcher throws exception.", previous.Exception.ToString()), null); break; } } previous.Dispose(); transport.Send(context); }
/// <summary> /// Sets the return value to the <see cref="ServerResponseContext"/>. /// </summary> /// <typeparam name="T">The type of the return value.</typeparam> /// <param name="context">The <see cref="ServerResponseContext"/> to be set the return value.</param> /// <param name="returnValue">The return value to be set.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="context"/> is <c>null</c>. /// </exception> protected void SetReturnValue <T>(ServerResponseContext context, T returnValue) { if (context == null) { throw new ArgumentNullException("context"); } Contract.EndContractBlock(); context.Serialize(returnValue, RpcErrorMessage.Success, this.SerializationContext.GetSerializer <T>()); }
/// <summary> /// Sets the exception to the <see cref="ServerResponseContext"/> as called method failure. /// </summary> /// <param name="context">The <see cref="ServerResponseContext"/> to be set the error.</param> /// <param name="operationId">The ID of operation which causes <paramref name="exception"/>.</param> /// <param name="exception">The exception to be set as the RPC error.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="context"/> is <c>null</c>. /// Or, <paramref name="exception"/> is <c>null</c>. /// </exception> /// <remarks> /// You should use <see cref="RpcException"/> derived class to represent application error. /// The runtime does not interpret other exception types except <see cref="ArgumentException"/> derviced class, /// so they are represented as <see cref="RpcError.CallError"/> in the lump. /// (<see cref="ArgumentException"/> derviced class is transformed to <see cref="P:RpcError.ArgumentError"/>. /// </remarks> protected void SetException(ServerResponseContext context, string operationId, Exception exception) { if (context == null) { throw new ArgumentNullException("context"); } if (exception == null) { throw new ArgumentNullException("exception"); } Contract.EndContractBlock(); context.Serialize <MessagePackObject>(MessagePackObject.Nil, InvocationHelper.HandleInvocationException(exception, operationId, this.IsDebugMode), this.SerializationContext.GetSerializer <MessagePackObject>()); }
/// <summary> /// Dispatches the specified request, and dispatches the response to the specified transport. /// </summary> /// <param name="serverTransport">The server transport the response to be dispatched.</param> /// <param name="requestContext">The request context.</param> internal void Dispatch(ServerTransport serverTransport, ServerRequestContext requestContext) { Contract.Requires(serverTransport != null); Contract.Requires(requestContext != null); ServerResponseContext responseContext = null; if (requestContext.MessageType == MessageType.Request) { responseContext = serverTransport.Manager.GetResponseContext(requestContext); } Task task; var operation = this.Dispatch(requestContext.MethodName); if (operation == null) { var error = new RpcErrorMessage(RpcError.NoMethodError, "Operation does not exist.", null); InvocationHelper.TraceInvocationResult <object>( requestContext.SessionId, requestContext.MessageType, requestContext.MessageId.GetValueOrDefault(), requestContext.MethodName, error, null ); if (responseContext != null) { task = Task.Factory.StartNew(() => responseContext.Serialize <object>(null, error, null)); } else { return; } } else { task = operation(requestContext, responseContext); } var sessionState = Tuple.Create(this._server, requestContext.SessionId, requestContext.MessageType == MessageType.Request ? requestContext.MessageId : default(int?), requestContext.MethodName); #if NET_4_5 task.ContinueWith((previous, state) => { var tuple = state as Tuple < ServerTransport, ServerResponseContext, Tuple <RpcServer, long, int?, string>; SendResponse(previous, tuple.Item1, tuple.Item2, tuple.Item3) }, Tuple.Create(serverTransport, responseContext, sessionState) ).ContinueWith((previous, state) => { HandleSendFailure(previous, state as Tuple <RpcServer, long, int?, string>); }, TaskContinuationOptions.OnlyOnFaulted, sessionState ); #else task.ContinueWith(previous => { SendResponse(previous, serverTransport, responseContext, sessionState); } ).ContinueWith(previous => { HandleSendFailure(previous, sessionState); }, TaskContinuationOptions.OnlyOnFaulted ); #endif }