public void TestHandleInvocationException_Null_IsNotDebugMode_AsRemoteRuntimeError() { var result = InvocationHelper.HandleInvocationException(null, "Method", false); Assert.That(result.Error, Is.EqualTo(RpcError.CallError)); Assert.That(result.Detail.AsDictionary()[RpcException.MessageKeyUtf8].AsString(), Is.Not.Null.And.Not.Empty); Assert.That(result.Detail.AsDictionary().ContainsKey(RpcException.DebugInformationKeyUtf8), Is.False); }
public void TestHandleArgumentDeserializationException_Null_IsNotDebugMode_DefaultString() { var result = InvocationHelper.HandleArgumentDeserializationException(null, null, false); Assert.That(result.IsSuccess, Is.False); Assert.That(result.Error, Is.EqualTo(RpcError.ArgumentError)); Assert.That(result.Detail.AsDictionary()[RpcException.MessageKeyUtf8].AsString(), Is.Not.Null.And.Not.Empty); Assert.That(result.Detail.AsDictionary().ContainsKey(RpcException.DebugInformationKeyUtf8), Is.False); }
protected sealed override Func <ServerRequestContext, ServerResponseContext, Task> Dispatch(string methodName) { // Ignore methodName return ((requestContext, responseContext) => { var argumentsUnpacker = requestContext.ArgumentsUnpacker; argumentsUnpacker.Read(); MessagePackObject[] args = MessagePackSerializer.Create <MessagePackObject[]>(_serializationContext).UnpackFrom(argumentsUnpacker); var messageId = requestContext.MessageId; return Task.Factory.StartNew( () => { MessagePackObject returnValue; try { this.BeginOperation(); try { returnValue = this._dispatch(methodName, messageId, args); } catch (ThreadAbortException ex) { this.HandleThreadAbortException(ex); returnValue = MessagePackObject.Nil; } finally { this.EndOperation(); } } catch (Exception exception) { if (responseContext != null) { base.SetException(responseContext, methodName, exception); } else { // notification InvocationHelper.HandleInvocationException(requestContext.SessionId, MessageType.Notification, requestContext.MessageId, requestContext.MethodName, exception, this.IsDebugMode); } return; } if (responseContext != null) { base.SetReturnValue(responseContext, returnValue); } } ); }); }
public void TestHandleInvocationException_NotNull_OtherException_IsDebugMode_AsRemoteRuntimeError() { var exception = new Exception(Guid.NewGuid().ToString()); var result = InvocationHelper.HandleInvocationException(exception, "Method", true); Assert.That(result.Error, Is.EqualTo(RpcError.CallError)); Assert.That(result.Detail.AsDictionary()[RpcException.MessageKeyUtf8].AsString(), Is.Not.Null.And.Not.Empty.And.StringContaining(exception.Message)); Assert.That(result.Detail.AsDictionary()[RpcException.DebugInformationKeyUtf8].AsString(), Is.StringContaining(exception.Message)); }
public void TestHandleInvocationException_NotNull_RpcException_IsDebugMode_AsCorrespondingErrorWithoutDebugInformation() { var exception = new RpcException(RpcError.MessageTooLargeError, Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); var result = InvocationHelper.HandleInvocationException(exception, "Method", false); Assert.That(result.Error, Is.EqualTo(exception.RpcError)); Assert.That(result.Detail.AsDictionary()[RpcException.MessageKeyUtf8].AsString(), Is.Not.Null.And.No.Empty.And.Not.StringContaining(exception.Message).And.Not.StringContaining(exception.DebugInformation)); Assert.That(result.Detail.AsDictionary().ContainsKey(RpcException.DebugInformationKeyUtf8), Is.False); }
public void TestHandleInvocationException_NotNull_ArgumentException_IsNotDebugMode_AsArgumentErrorWithoutDebugInformation() { var exception = new ArgumentException(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); var result = InvocationHelper.HandleInvocationException(exception, "Method", false); Assert.That(result.Error, Is.EqualTo(RpcError.ArgumentError)); Assert.That(result.Detail.AsDictionary()[RpcException.MessageKeyUtf8].AsString(), Is.StringContaining(exception.ParamName)); Assert.That(result.Detail.AsDictionary().ContainsKey(RpcException.DebugInformationKeyUtf8), Is.False); }
public void TestHandleArgumentDeserializationException_NotNull_IsNotDebugMode_DoesNotIncludeFullExceptionInfo() { var exception = new Exception(Guid.NewGuid().ToString()); string parameterName = Guid.NewGuid().ToString(); var result = InvocationHelper.HandleArgumentDeserializationException(exception, parameterName, false); Assert.That(result.IsSuccess, Is.False); Assert.That(result.Error, Is.EqualTo(RpcError.ArgumentError)); Assert.That(result.Detail.AsDictionary()[RpcException.MessageKeyUtf8].AsString(), Is.StringContaining(parameterName)); Assert.That(result.Detail.AsDictionary().ContainsKey(RpcException.DebugInformationKeyUtf8), Is.False); }
private static void HandleInvocationResult(Task previous, Tuple <AsyncServiceInvoker <T>, long, int, string, ServerResponseContext, RpcErrorMessage> closureState) { var @this = closureState.Item1; var sessionId = closureState.Item2; var messageId = closureState.Item3; var operationId = closureState.Item4; var responseContext = closureState.Item5; var error = closureState.Item6; T result = default(T); try { if (previous != null) { if (error.IsSuccess) { if (previous.Exception != null) { error = InvocationHelper.HandleInvocationException( sessionId, responseContext == null ? MessageType.Notification : MessageType.Request, responseContext == null ? default(int?) : messageId, operationId, previous.Exception.InnerException, @this.IsDebugMode ); } else if (@this._returnValueSerializer != null) { result = (previous as Task <T>).Result; } } previous.Dispose(); } InvocationHelper.TraceInvocationResult(sessionId, responseContext == null ? MessageType.Notification : MessageType.Request, messageId, @this.OperationId, error, result); } finally { SafeStopLogicalOperation(); } if (responseContext != null) { responseContext.Serialize(result, error, @this._returnValueSerializer); } }
public void TestTrace_SuccessAtLeast() { var oldLevel = MsgPackRpcServerDispatchTrace.Source.Switch.Level; try { MsgPackRpcServerDispatchTrace.Source.Switch.Level = System.Diagnostics.SourceLevels.All; InvocationHelper.TraceInvocationResult <object>(1, Rpc.Protocols.MessageType.Request, 1, "TracingTest", RpcErrorMessage.Success, null); InvocationHelper.TraceInvocationResult <object>(1, Rpc.Protocols.MessageType.Request, 1, "TracingTest", new RpcErrorMessage(RpcError.RemoteRuntimeError, "Description", "DebugInformation"), null); } finally { MsgPackRpcServerDispatchTrace.Source.Switch.Level = oldLevel; } }
/// <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>()); }
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); }
public sealed override Task InvokeAsync(ServerRequestContext requestContext, ServerResponseContext responseContext) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } Contract.Ensures(Contract.Result <Task>() != null); var messageId = requestContext.MessageId; var arguments = requestContext.ArgumentsUnpacker; bool readMustSuccess = arguments.Read(); Contract.Assert(readMustSuccess, "Arguments is not an array."); Contract.Assert(arguments.IsArrayHeader); SafeStartLogicalOperation(); if (MsgPackRpcServerDispatchTrace.ShouldTrace(MsgPackRpcServerDispatchTrace.OperationStart)) { MsgPackRpcServerDispatchTrace.TraceData( MsgPackRpcServerDispatchTrace.OperationStart, "Operation starting.", responseContext == null ? MessageType.Notification : MessageType.Request, messageId, this.OperationId ); } AsyncInvocationResult result; try { result = this.InvokeCore(arguments); } catch (Exception ex) { result = new AsyncInvocationResult(InvocationHelper.HandleInvocationException(requestContext.SessionId, requestContext.MessageType, requestContext.MessageId, this.OperationId, ex, this.IsDebugMode)); } var tuple = Tuple.Create(this, requestContext.SessionId, messageId.GetValueOrDefault(), this.OperationId, responseContext, result.InvocationError); if (result.AsyncTask == null) { return(Task.Factory.StartNew(state => HandleInvocationResult(null, state as Tuple <AsyncServiceInvoker <T>, long, int, string, ServerResponseContext, RpcErrorMessage>), tuple)); } else { #if NET_4_5 return (result.AsyncTask.ContinueWith( (previous, state) => HandleInvocationResult( previous, state as Tuple <AsyncServiceInvoker <T>, long, int, string, ServerResponseContext, RpcErrorMessage> ), tuple )); #else return (result.AsyncTask.ContinueWith( previous => HandleInvocationResult( previous, tuple ) )); #endif } }
/// <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 }