예제 #1
0
        /// <summary>
        /// Invokes a method on the server.
        /// </summary>
        /// <typeparam name="TResult">The type of result from the method.</typeparam>
        /// <param name="expression">The method to invoke.</param>
        /// <param name="cancellationToken">A token to cancel the request.</param>
        /// <returns>The method result.</returns>
        /// <exception cref="PipeInvokeFailedException">Thrown when the invoked method throws an exception.</exception>
        /// <exception cref="IOException">Thrown when there is an issue with the pipe communication.</exception>
        /// <exception cref="OperationCanceledException">Thrown when the cancellation token is invoked.</exception>
        public async Task <TResult> InvokeAsync <TResult>(Expression <Func <TRequesting, TResult> > expression, CancellationToken cancellationToken = default)
        {
            // Sync with result

            Utilities.EnsureReadyForInvoke(this.pipeHost.State, this.pipeHost.PipeFault);

            PipeResponse response = await this.GetResponseFromExpressionAsync(expression, cancellationToken).ConfigureAwait(false);

            if (response.Succeeded)
            {
                if (Utilities.TryConvert(response.Data, typeof(TResult), out object result))
                {
                    return((TResult)result);
                }
                else
                {
                    throw new InvalidOperationException($"Unable to convert returned value to '{typeof(TResult).Name}'.");
                }
            }
            else
            {
                ThrowCoveoException(response);
                ThrowGenericException(response);

                throw new PipeInvokeFailedException(response.Error);
            }
        }
예제 #2
0
        /// <summary>
        /// Handles a response message received from a remote endpoint.
        /// </summary>
        /// <param name="response">The response message to handle.</param>
        public void HandleResponse(PipeResponse response)
        {
            if (!this.pendingCalls.TryGetValue(response.CallId, out PendingCall pendingCall))
            {
                throw new InvalidOperationException($"No pending call found for ID {response.CallId}");
            }

            pendingCall.TaskCompletionSource.TrySetResult(response);
        }
예제 #3
0
        /// <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.
            }
        }
예제 #4
0
        /// <summary>
        /// Invokes a method on the server.
        /// </summary>
        /// <param name="expression">The method to invoke.</param>
        /// <param name="cancellationToken">A token to cancel the request.</param>
        /// <exception cref="PipeInvokeFailedException">Thrown when the invoked method throws an exception.</exception>
        /// <exception cref="IOException">Thrown when there is an issue with the pipe communication.</exception>
        /// <exception cref="OperationCanceledException">Thrown when the cancellation token is invoked.</exception>
        public async Task InvokeAsync(Expression <Func <TRequesting, Task> > expression, CancellationToken cancellationToken = default)
        {
            // Async, no result

            Utilities.EnsureReadyForInvoke(this.pipeHost.State, this.pipeHost.PipeFault);

            PipeResponse response = await this.GetResponseFromExpressionAsync(expression, cancellationToken).ConfigureAwait(false);

            if (!response.Succeeded)
            {
                throw new PipeInvokeFailedException(response.Error);
            }
        }
예제 #5
0
        private static void ThrowExceptionForAssembly(PipeResponse response, Assembly assembly)
        {
            var type = assembly.GetType(response.Exception.ExceptionType);

            if (response.Exception.InnerException != null)
            {
                var innerType      = assembly.GetType(response.Exception.InnerException.ExceptionType);
                var innerException = Activator.CreateInstance(innerType, response.Exception.InnerException.ExceptionMessage) as Exception;
                throw Activator.CreateInstance(type, response.Exception.ExceptionMessage, innerException) as Exception;
            }

            throw Activator.CreateInstance(type, response.Exception.ExceptionMessage) as Exception;
        }
예제 #6
0
        private void ThrowCoveoException(PipeResponse response)
        {
            if (response.Exception != null && !string.IsNullOrEmpty(response.Exception.ExceptionType))
            {
                if (response.Exception.ExceptionType.Contains(COVEO_DOCUMENTPROCESSING_EXCEPTION))
                {
                    var assembly = Assembly.Load(COVEOCUSTOMCRAWLERS_DOCUMENTPROCESSING_ASSEMBLY);

                    ThrowExceptionForAssembly(response, assembly);
                }
                else if (response.Exception.ExceptionType.Contains(COVEO_EXCEPTION))
                {
                    var assembly = Assembly.Load(COVEOCUSTOMCRAWLERS_ASSEMBLY);

                    ThrowExceptionForAssembly(response, assembly);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Handles a response message received from a remote endpoint.
        /// </summary>
        /// <param name="response">The response message to handle.</param>
        public void HandleResponse(PipeResponse response)
        {
            PendingCall pendingCall = null;

            lock (this.pendingCallsLock)
            {
                if (this.pendingCalls.TryGetValue(response.CallId, out pendingCall))
                {
                    // Call has completed. Remove from pending list.
                    this.pendingCalls.Remove(response.CallId);
                }
                else
                {
                    throw new InvalidOperationException($"No pending call found for ID {response.CallId}");
                }
            }

            // Mark method call task as completed.
            pendingCall.TaskCompletionSource.TrySetResult(response);
        }
예제 #8
0
        private void ThrowGenericException(PipeResponse response)
        {
            if (response.Exception != null && !string.IsNullOrEmpty(response.Exception.ExceptionType))
            {
                var type = Type.GetType(response.Exception.ExceptionType);

                if (response.Exception.InnerException != null)
                {
                    var innerType      = Type.GetType(response.Exception.InnerException.ExceptionType);
                    var innerException = Activator.CreateInstance(innerType, response.Exception.InnerException.ExceptionMessage) as Exception;
                    throw Activator.CreateInstance(type, response.Exception.ExceptionMessage, innerException) as Exception;
                }

                if (response.Exception.ExceptionType.Contains(ARGUMENT_EXCEPTION))
                {
                    throw Activator.CreateInstance(type, null, response.Exception.ExceptionMessage) as Exception;
                }

                throw Activator.CreateInstance(type, response.Exception.ExceptionMessage) as Exception;
            }
        }
예제 #9
0
        /// <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);
                PipeRequest request = JsonConvert.DeserializeObject <PipeRequest>(json, serializerSettings);

                if (this.RequestHandler == null)
                {
                    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);
                PipeResponse response = JsonConvert.DeserializeObject <PipeResponse>(json, serializerSettings);

                if (this.ResponseHandler == null)
                {
                    throw new InvalidOperationException("Response received but this endpoint is not set up to make requests.");
                }

                this.ResponseHandler.HandleResponse(response);
                break;

            default:
                throw new InvalidOperationException($"Unrecognized message type: {message.messageType}");
            }
        }
예제 #10
0
 /// <summary>
 /// Sends a response.
 /// </summary>
 /// <param name="response">The response to send.</param>
 /// <param name="cancellationToken">A token to cancel the operation.</param>
 public Task SendResponseAsync(PipeResponse response, CancellationToken cancellationToken)
 {
     return(this.SendMessageAsync(MessageType.Response, response, cancellationToken));
 }
예제 #11
0
        /// <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()));
            }
        }