/// <summary> /// Invokes the method with the specified parameters, returns the result of the method /// </summary> /// <exception cref="RpcInvalidParametersException">Thrown when conversion of parameters fails or when invoking the method is not compatible with the parameters</exception> /// <param name="parameters">List of parameters to invoke the method with</param> /// <returns>The result of the invoked method</returns> private async Task <object> InvokeAsync(RpcMethodInfo methodInfo, RpcPath path) { object obj = null; if (this.serviceProvider != null) { //Use service provider (if exists) to create instance var objectFactory = ActivatorUtilities.CreateFactory(methodInfo.Method.DeclaringType, new Type[0]); obj = objectFactory(this.serviceProvider, null); } if (obj == null) { //Use reflection to create instance if service provider failed or is null obj = Activator.CreateInstance(methodInfo.Method.DeclaringType); } try { object returnObj = methodInfo.Method.Invoke(obj, methodInfo.ConvertedParameters); returnObj = await DefaultRpcInvoker.HandleAsyncResponses(returnObj); return(returnObj); } catch (TargetInvocationException ex) { var routeInfo = new RpcRouteInfo(methodInfo, path, this.serviceProvider); //Controller error handling RpcErrorFilterAttribute errorFilter = methodInfo.Method.DeclaringType.GetTypeInfo().GetCustomAttribute <RpcErrorFilterAttribute>(); if (errorFilter != null) { OnExceptionResult result = errorFilter.OnException(routeInfo, ex.InnerException); if (!result.ThrowException) { return(result.ResponseObject); } if (result.ResponseObject is Exception rEx) { throw rEx; } } throw new RpcUnknownException("Exception occurred from target method execution.", ex); } catch (Exception ex) { throw new RpcInvalidParametersException("Exception from attempting to invoke method. Possibly invalid parameters for method.", ex); } }
/// <summary> /// Finds the matching Rpc method for the current request /// </summary> /// <param name="route">Rpc route for the current request</param> /// <param name="request">Current Rpc request</param> /// <param name="parameterList">Paramter list parsed from the request</param> /// <param name="serviceProvider">(Optional)IoC Container for rpc method controllers</param> /// <param name="jsonSerializerSettings">Json serialization settings that will be used in serialization and deserialization for rpc requests</param> /// <returns>The matching Rpc method to the current request</returns> private RpcMethod GetMatchingMethod(RpcRoute route, RpcRequest request, out object[] parameterList, IServiceProvider serviceProvider = null, JsonSerializerSettings jsonSerializerSettings = null) { if (route == null) { throw new ArgumentNullException(nameof(route)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } this.logger?.LogDebug($"Attempting to match Rpc request to a method '{request.Method}'"); List <RpcMethod> methods = DefaultRpcInvoker.GetRpcMethods(route, serviceProvider, jsonSerializerSettings); //Case insenstive check for hybrid approach. Will check for case sensitive if there is ambiguity methods = methods .Where(m => string.Equals(m.Method, request.Method, StringComparison.OrdinalIgnoreCase)) .ToList(); RpcMethod rpcMethod = null; parameterList = null; int originalMethodCount = methods.Count; if (methods.Count > 0) { List <RpcMethod> potentialMatches = new List <RpcMethod>(); foreach (RpcMethod method in methods) { bool matchingMethod; if (request.ParameterMap != null) { matchingMethod = method.HasParameterSignature(request.ParameterMap, out parameterList); } else { matchingMethod = method.HasParameterSignature(request.ParameterList, out parameterList); } if (matchingMethod) { potentialMatches.Add(method); } } if (potentialMatches.Count > 1) { //Try to remove ambiguity with case sensitive check potentialMatches = potentialMatches .Where(m => string.Equals(m.Method, request.Method, StringComparison.Ordinal)) .ToList(); if (potentialMatches.Count != 1) { this.logger?.LogError("More than one method matched the rpc request. Unable to invoke due to ambiguity."); throw new RpcMethodNotFoundException(); } } if (potentialMatches.Count == 1) { rpcMethod = potentialMatches.First(); } } if (rpcMethod == null) { this.logger?.LogError("No methods matched request."); throw new RpcMethodNotFoundException(); } this.logger?.LogDebug("Request was matched to a method"); return(rpcMethod); }
/// <summary> /// Finds the matching Rpc method for the current request /// </summary> /// <param name="route">Rpc route for the current request</param> /// <param name="request">Current Rpc request</param> /// <param name="parameterList">Paramter list parsed from the request</param> /// <param name="serviceProvider">(Optional)IoC Container for rpc method controllers</param> /// <param name="jsonSerializerSettings">Json serialization settings that will be used in serialization and deserialization for rpc requests</param> /// <returns>The matching Rpc method to the current request</returns> private RpcMethod GetMatchingMethod(RpcRoute route, RpcRequest request, out object[] parameterList, IServiceProvider serviceProvider = null, JsonSerializerSettings jsonSerializerSettings = null) { if (route == null) { throw new ArgumentNullException(nameof(route)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } this.Logger?.LogDebug($"Attempting to match Rpc request to a method '{request.Method}'"); List <RpcMethod> methods = DefaultRpcInvoker.GetRpcMethods(route, serviceProvider, jsonSerializerSettings); methods = methods .Where(m => string.Equals(m.Method, request.Method, StringComparison.OrdinalIgnoreCase)) .ToList(); RpcMethod rpcMethod = null; parameterList = null; if (methods.Count > 1) { foreach (RpcMethod method in methods) { bool matchingMethod; if (request.ParameterMap != null) { matchingMethod = method.HasParameterSignature(request.ParameterMap, out parameterList); } else { matchingMethod = method.HasParameterSignature(request.ParameterList); parameterList = request.ParameterList; } if (matchingMethod) { if (rpcMethod != null) //If already found a match { throw new RpcAmbiguousMethodException(); } rpcMethod = method; } } } else if (methods.Count == 1) { //Only signature check for methods that have the same name for performance reasons rpcMethod = methods.First(); if (request.ParameterMap != null) { bool signatureMatch = rpcMethod.TryParseParameterList(request.ParameterMap, out parameterList); if (!signatureMatch) { throw new RpcMethodNotFoundException(); } } else { parameterList = request.ParameterList; } } if (rpcMethod == null) { throw new RpcMethodNotFoundException(); } this.Logger?.LogDebug("Request was matched to a method"); return(rpcMethod); }