/// <summary> /// Creates <see cref="ServerResponseContext"/> which contains specified required states. /// </summary> /// <param name="transport">The transport to be bound to the context.</param> /// <returns><see cref="ServerResponseContext"/> for the unit testing argument.</returns> public static ServerResponseContext CreateResponseContext(IContextBoundableTransport transport) { var result = new ServerResponseContext(); result.SetTransport(transport); return(result); }
/// <summary> /// Performs protocol specific asynchronous 'Send' operation. /// </summary> /// <param name="context">Context information.</param> protected sealed override void SendCore( ServerResponseContext context ) { // Manager stores the socket which is dedicated socket to this transport in the AcceptSocket property. if ( !this.BoundSocket.SendToAsync( context.SocketContext ) ) { context.SetCompletedSynchronously(); this.OnSent( context ); } }
private void TestGetServiceInvokerCore <TArg1, TArg2, TResult>( EventHandler <ServiceInvokedEventArgs <TResult> > invoked, RpcServerConfiguration configuration, TArg1 arg1, TArg2 arg2, Action <ServerResponseContext> assertion ) { using (var target = new ServiceInvokerGenerator(true)) using (var server = new RpcServer()) using (var transportManager = new NullServerTransportManager(server)) using (var transport = new NullServerTransport(transportManager)) { var service = new Service <TArg1, TArg2, TResult>(); service.Invoked += invoked; var serviceDescription = new ServiceDescription("Service", () => service); var targetOperation = service.GetType().GetMethod("Invoke"); using (var requestContext = new ServerRequestContext()) { requestContext.ArgumentsBufferPacker = Packer.Create(requestContext.ArgumentsBuffer, false); requestContext.ArgumentsBufferPacker.PackArrayHeader(2); requestContext.ArgumentsBufferPacker.Pack(arg1); requestContext.ArgumentsBufferPacker.Pack(arg2); requestContext.ArgumentsBuffer.Position = 0; requestContext.MessageId = 123; requestContext.ArgumentsUnpacker = Unpacker.Create(requestContext.ArgumentsBuffer, false); var responseContext = new ServerResponseContext(); responseContext.SetTransport(transport); try { var result = target.GetServiceInvoker(RpcServerRuntime.Create(configuration, this._serializationContext), serviceDescription, targetOperation); result.InvokeAsync(requestContext, responseContext).Wait(TimeSpan.FromSeconds(1)); assertion(responseContext); } finally { if (this._isDumpEnabled) { try { target.Dump(); } catch (Exception ex) { Console.Error.WriteLine("Failed to dump: {0}", ex); } } } } } }
/// <summary> /// Performs protocol specific asynchronous 'Send' operation. /// </summary> /// <param name="context">Context information.</param> protected override void SendCore( ServerResponseContext context ) { var handler = this.Sent; if ( handler != null ) { handler( this, new SentEventArgs( context ) ); } return; }
/// <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>()); }
private static void TestCore( Action<ServerResponseContext, ServerTransport> test ) { using ( var server = new RpcServer() ) using ( var manager = new NullServerTransportManager( server ) ) using ( var transport = new NullServerTransport( manager ) ) using ( var target = new ServerResponseContext() ) { target.SetTransport( transport ); test( target, transport ); } }
/// <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>()); }
public void TestInvokeAsync_Success_TaskSetSerializedReturnValue() { using (var server = new RpcServer()) using (var transportManager = new NullServerTransportManager(server)) using (var transport = new NullServerTransport(transportManager)) { ServerRequestContext requestContext = DispatchTestHelper.CreateRequestContext(); ServerResponseContext responseContext = DispatchTestHelper.CreateResponseContext(transport); using (var result = new Target(null, RpcErrorMessage.Success).InvokeAsync(requestContext, responseContext)) { result.Wait(); } Assert.That(responseContext.GetReturnValueData(), Is.EqualTo(new byte[] { 123 })); Assert.That(responseContext.GetErrorData(), Is.EqualTo(new byte[] { 0xC0 })); } }
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 void TestInvokeAsync_MethodError_TaskSetSerializedError() { using (var server = new RpcServer()) using (var transportManager = new NullServerTransportManager(server)) using (var transport = new NullServerTransport(transportManager)) { ServerRequestContext requestContext = DispatchTestHelper.CreateRequestContext(); ServerResponseContext responseContext = DispatchTestHelper.CreateResponseContext(transport); using (var result = new Target(null, new RpcErrorMessage(RpcError.ArgumentError, MessagePackObject.Nil)).InvokeAsync(requestContext, responseContext)) { result.Wait(); } var error = Unpacking.UnpackObject(responseContext.GetErrorData()); var errorDetail = Unpacking.UnpackObject(responseContext.GetReturnValueData()); Assert.That(error.Value.Equals(RpcError.ArgumentError.Identifier)); Assert.That(errorDetail.Value.IsNil, Is.True); } }
public void TestInvokeAsync_FatalError_TaskSetSerializedError() { using (var server = new RpcServer()) using (var transportManager = new NullServerTransportManager(server)) using (var transport = new NullServerTransport(transportManager)) { ServerRequestContext requestContext = DispatchTestHelper.CreateRequestContext(); ServerResponseContext responseContext = DispatchTestHelper.CreateResponseContext(transport); using (var result = new Target(new Exception("FAIL"), RpcErrorMessage.Success).InvokeAsync(requestContext, responseContext)) { result.Wait(); } var error = Unpacking.UnpackObject(responseContext.GetErrorData()); var errorDetail = Unpacking.UnpackObject(responseContext.GetReturnValueData()); Assert.That(error.Value.Equals(RpcError.CallError.Identifier)); Assert.That(errorDetail.Value.IsNil, Is.False); } }
/// <summary> /// Invokes target service operation asynchronously. /// </summary> /// <param name="requestContext"> /// The context object to hold request data. /// Note that properties of the context is only valid until this method returns. /// That is, it will be unpredectable state in the asynchronous operation. /// </param> /// <param name="responseContext"> /// The context object to pack response value or error. /// This is <c>null</c> for the notification messages. /// </param> /// <returns> /// <see cref="Task"/> to control entire process including sending response. /// </returns> public abstract Task InvokeAsync(ServerRequestContext requestContext, ServerResponseContext responseContext);
protected override void SendCore( ServerResponseContext context ) { this._manager.SendAsync( context ) .ContinueWith( previous => this.OnSent( context ) ).Wait( this._receivingCancellationTokenSource.Token ); }
protected override void SendCore( ServerResponseContext context ) { Contract.Requires( context != null ); }
internal SentEventArgs( ServerResponseContext context ) { this._context = context; }
public void InvokeSetReturnValue <T>(ServerResponseContext responseContext, T returnValue) { this.SetReturnValue(responseContext, returnValue); }
/// <summary> /// Creates <see cref="ServerResponseContext"/> which contains specified required states. /// </summary> /// <param name="transport">The transport to be bound to the context.</param> /// <returns><see cref="ServerResponseContext"/> for the unit testing argument.</returns> public static ServerResponseContext CreateResponseContext( IContextBoundableTransport transport ) { var result = new ServerResponseContext(); result.SetTransport( transport ); return result; }
public void InvokeSetException(ServerResponseContext responseContext, string operationId, Exception exception) { this.SetException(responseContext, operationId, exception); }
/// <summary> /// Invokes target service operation asynchronously. /// </summary> /// <param name="requestContext"> /// The context object to hold request data. /// Note that properties of the context is only valid until this method returns. /// That is, it will be unpredectable state in the asynchronous operation. /// </param> /// <param name="responseContext"> /// The context object to pack response value or error. /// This is <c>null</c> for the notification messages. /// </param> /// <returns> /// <see cref="Task"/> to control entire process including sending response. /// </returns> public abstract Task InvokeAsync( ServerRequestContext requestContext, ServerResponseContext responseContext );
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 }
/// <summary> /// Returns the response context to the pool. /// </summary> /// <param name="context">The response to the pool.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="context"/> is <c>null</c>. /// </exception> protected internal void ReturnResponseContext( ServerResponseContext context ) { if ( context == null ) { throw new ArgumentNullException( "context" ); } Contract.EndContractBlock(); context.Clear(); context.UnboundTransport(); this.ResponseContextPool.Return( context ); }
/// <summary> /// Performs protocol specific asynchronous 'Send' operation. /// </summary> /// <param name="context">Context information.</param> protected sealed override void SendCore( ServerResponseContext context ) { Contract.Assert( this.BoundSocket != null ); if ( !this.BoundSocket.SendAsync( context.SocketContext ) ) { context.SetCompletedSynchronously(); this.OnSent( context ); } }