/// <summary> /// Handles a request message received from a remote endpoint. /// </summary> /// <param name="request">The request message.</param> public async void HandleRequest(PipeRequest request) { try { PipeResponse response = await this.HandleRequestAsync(request).ConfigureAwait(false); await this.pipeStreamWrapper.SendResponseAsync(response, CancellationToken.None).ConfigureAwait(false); } catch (Exception) { // If the pipe has closed and can't hear the response, we can't let the other end know about it, so we just eat the exception. } }
/// <summary> /// Gets a pipe response for the given pipe request. /// </summary> /// <param name="request">The request to send.</param> /// <param name="cancellationToken">A token to cancel the request.</param> /// <returns>The pipe response.</returns> private async Task <PipeResponse> GetResponseAsync(PipeRequest request, CancellationToken cancellationToken) { var pendingCall = new PendingCall(); this.pendingCalls.Add(request.CallId, pendingCall); await this.pipeStreamWrapper.SendRequestAsync(request, cancellationToken).ConfigureAwait(false); cancellationToken.Register( () => { pendingCall.TaskCompletionSource.TrySetException(new OperationCanceledException("Request has been canceled.")); }, false); return(await pendingCall.TaskCompletionSource.Task.ConfigureAwait(false)); }
/// <summary> /// Processes the next message on the input stream. /// </summary> /// <param name="cancellationToken">A token to cancel the operation.</param> public async Task ProcessMessageAsync(CancellationToken cancellationToken) { var message = await this.ReadMessageAsync(cancellationToken).ConfigureAwait(false); string json = message.jsonPayload; switch (message.messageType) { case MessageType.Request: //this.logger.Log(() => "Handling request:" + Environment.NewLine + json); nlogger_.Trace($"ProcessMessageAsync: Handling request: [{json}]"); PipeRequest request = JsonConvert.DeserializeObject <PipeRequest>(json, serializerSettings); if (this.RequestHandler == null) { nlogger_.Trace("ProcessMessageAsync: throwing - Request received but this endpoint is not set up to handle requests"); throw new InvalidOperationException("Request received but this endpoint is not set up to handle requests."); } this.RequestHandler.HandleRequest(request); break; case MessageType.Response: //this.logger.Log(() => "Handling response:" + Environment.NewLine + json); nlogger_.Trace($"ProcessMessageAsync: Handling response: [{json}]"); PipeResponse response = JsonConvert.DeserializeObject <PipeResponse>(json, serializerSettings); if (this.ResponseHandler == null) { nlogger_.Trace("ProcessMessageAsync: throwing - Response received but this endpoint is not set up to make requests"); throw new InvalidOperationException("Response received but this endpoint is not set up to make requests."); } this.ResponseHandler.HandleResponse(response); break; default: nlogger_.Trace($"ProcessMessageAsync: throwing - Unrecognized message type: {message.messageType}"); throw new InvalidOperationException($"Unrecognized message type: {message.messageType}"); } }
/// <summary> /// Gets a response from the given expression. /// </summary> /// <param name="expression">The expression to execute.</param> /// <param name="cancellationToken">A token to cancel the request.</param> /// <returns>A response for the given expression.</returns> private async Task <PipeResponse> GetResponseFromExpressionAsync(Expression expression, CancellationToken cancellationToken) { PipeRequest request = this.CreateRequest(expression); return(await this.GetResponseAsync(request, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Sends a request. /// </summary> /// <param name="request">The request to send.</param> /// <param name="cancellationToken">A token to cancel the operation.</param> public Task SendRequestAsync(PipeRequest request, CancellationToken cancellationToken) { return(this.SendMessageAsync(MessageType.Request, request, cancellationToken)); }
/// <summary> /// Handles a request from a remote endpoint. /// </summary> /// <param name="request">The request.</param> /// <returns>The response.</returns> private async Task <PipeResponse> HandleRequestAsync(PipeRequest request) { if (this.handlerFactoryFunc == null) { return(PipeResponse.Failure(request.CallId, $"No handler implementation registered for interface '{typeof(THandling).FullName}' found.")); } THandling handlerInstance = this.handlerFactoryFunc(); if (handlerInstance == null) { return(PipeResponse.Failure(request.CallId, $"Handler implementation returned null for interface '{typeof(THandling).FullName}'")); } MethodInfo method = handlerInstance.GetType().GetMethod(request.MethodName); if (method == null) { return(PipeResponse.Failure(request.CallId, $"Method '{request.MethodName}' not found in interface '{typeof(THandling).FullName}'.")); } ParameterInfo[] paramInfoList = method.GetParameters(); if (paramInfoList.Length != request.Parameters.Length) { return(PipeResponse.Failure(request.CallId, $"Parameter count mismatch for method '{request.MethodName}'.")); } Type[] genericArguments = method.GetGenericArguments(); if (genericArguments.Length != request.GenericArguments.Length) { return(PipeResponse.Failure(request.CallId, $"Generic argument count mismatch for method '{request.MethodName}'.")); } if (paramInfoList.Any(info => info.IsOut || info.ParameterType.IsByRef)) { return(PipeResponse.Failure(request.CallId, $"ref parameters are not supported. Method: '{request.MethodName}'")); } object[] args = new object[paramInfoList.Length]; for (int i = 0; i < args.Length; i++) { object origValue = request.Parameters[i]; Type destType = paramInfoList[i].ParameterType; if (destType.IsGenericParameter) { destType = request.GenericArguments[destType.GenericParameterPosition]; } if (Utilities.TryConvert(origValue, destType, out object arg)) { args[i] = arg; } else { return(PipeResponse.Failure(request.CallId, $"Cannot convert value of parameter '{paramInfoList[i].Name}' ({origValue}) from {origValue.GetType().Name} to {destType.Name}.")); } } try { if (method.IsGenericMethod) { method = method.MakeGenericMethod(request.GenericArguments); } object result = method.Invoke(handlerInstance, args); if (result is Task) { await((Task)result).ConfigureAwait(false); var resultProperty = result.GetType().GetProperty("Result"); return(PipeResponse.Success(request.CallId, resultProperty?.GetValue(result))); } else { return(PipeResponse.Success(request.CallId, result)); } } catch (Exception exception) { return(PipeResponse.Failure(request.CallId, exception.ToString())); } }