public void GetMatchingMethod_ListParam_Match_Snake_Case(string parameterNameCase) { DefaultRequestMatcher matcher = this.GetMatcher(); IEnumerable <KeyValuePair <string, RpcParameterType> > parameters = new[] { new KeyValuePair <string, RpcParameterType>(parameterNameCase, RpcParameterType.String) }; string methodName = nameof(MethodMatcherController.SnakeCaseParams); var requestSignature = RpcRequestSignature.Create(methodName, parameters); RpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature); Assert.NotNull(methodInfo); MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !; Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo); Assert.Single(methodInfo.Parameters); Assert.False(methodInfo.Parameters[0].IsOptional); Assert.Equal(typeof(string), methodInfo.Parameters[0].RawType); Assert.Equal(RpcParameterType.String, methodInfo.Parameters[0].Type); Assert.True(RpcUtil.NamesMatch(methodInfo.Parameters[0].Name, parameterNameCase)); }
private HttpApiClient GetClient(RpcMethodInfo toCall) { HttpClient httpClient = new HttpClient(Build(), false); httpClient.Timeout = config.TimeOut; httpClient.BaseAddress = new System.Uri(config.urlProvider.GetEndpoint(toCall)); return(new HttpApiClient(httpClient, serializer)); }
public async Task <object> Invoke(RpcMethodInfo toCall, object[] param) { if (param == null) { param = new object[0]; } //This format is recognized by the default implementation of the server. //The base url for the request is expected to be set on the HttpClient string requestUri = CreateIdString(toCall); var theHttpRequest = new HttpRequestMessage(HttpMethod.Post, requestUri); var outstream = new System.IO.MemoryStream(); var theSerializer = serializer; switch (param.Length) { case 0: break; case 1: theSerializer.ToStream(outstream, param[0]); break; default: theSerializer.ToStream(outstream, param); break; } outstream.Position = 0; theHttpRequest.Content = new StreamContent(outstream); theHttpRequest.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(theSerializer.ProduceMimeType); var response = await httpClient.SendAsync(theHttpRequest); if (response.IsSuccessStatusCode) { if (toCall.ReturnType == typeof(void) | toCall.ReturnType == typeof(Task)) { return(null); } var ret = theSerializer.FromStream(await response.Content.ReadAsStreamAsync(), toCall.ReturnType); return(ret); } else if ((int)response.StatusCode >= 500) { var remoteExceptionInfo = theSerializer.FromStream(await response.Content.ReadAsStreamAsync(), typeof(RemoteExceptionInfo)); throw new WebRpcCallFailedException((RemoteExceptionInfo)remoteExceptionInfo); } else { throw new HttpRequestException($"{response.StatusCode} {response.Content.ReadAsStringAsync().Result}"); } }
public ResponseCodeGen(RpcMethodInfo hRpcInfo, int iProtocolCounter) { Name = string.Format("Response{0}", hRpcInfo.Method.Name); RpcInfo = hRpcInfo; string sReturnProperty = hRpcInfo.Method.ReturnType != typeof(void) ? string.Format("public {0} Data;", hRpcInfo.Method.ReturnType.AsKeyword()) : string.Empty; string sEncodeParam = hRpcInfo.Method.ReturnType != typeof(void) ? string.Format("{0} hData", hRpcInfo.Method.ReturnType.AsKeyword()) : string.Empty; string sWriteCalls = hRpcInfo.Method.ReturnType != typeof(void) ? "m_hWriter.Write(hData);" : string.Empty; string sLoadCalls = hRpcInfo.Method.ReturnType != typeof(void) ? string.Format("Data = hReader.Read{0}();", hRpcInfo.Method.ReturnType.Name) : string.Empty; string sResult = string.Format(@" using System; using System.Collections.Generic; using System.IO; using Netbase.Shared; namespace {0} {{ [NetbasePacket({1})] public class {2} : Packet {{ {3} public {4}() : base({1}, {5}) {{ }} public void Encode({6}) {{ this.BeginEncode(); {7} this.EndEncode(); }} public override void LoadData(BinaryReader hReader) {{ base.LoadData(hReader); {8} }} }} }}", RpcInfo.Service.Pair.Client.Namespace, iProtocolCounter, Name, sReturnProperty, Name, 1024, sEncodeParam, sWriteCalls, sLoadCalls); Code = sResult; }
public RequestActionCodeGen(IRequestActionBuilder hBuilder, RpcMethodInfo hRpc) { Name = string.Format("Request{0}Action", hRpc.Method.Name); RpcInfo = hRpc; string sResult = string.Format(@" using System; using System.Reflection; using Netbase.Shared; {0} namespace {1} {{ //{10} public class {2} : {3}, IAction {{ private const string m_sMethodName = ""{4}""; private static MethodInfo m_hMethod; {5} public {2}() : base() {{ {6} }} public void Execute(IService hService, ISession hContext) {{ if(m_hMethod == null) m_hMethod = hService.GetType().GetMethod(m_sMethodName); {7} {8} {9} }} }} }} ", hBuilder.UsingNamespace(RpcInfo.Service), //0 - using ProjName.Service; RpcInfo.Service.Namespace, //1 Name, //2 RpcInfo.Request.Name, //3 hBuilder.MethodToCall(RpcInfo), //4 hBuilder.ResponseDeclaration(RpcInfo.Response), //5 - private ResponseSomeThing m_hResponse hBuilder.ResponseAllocation(RpcInfo.Response), //6 - m_hResponse = new ResponseSomeThing(); hBuilder.ResponseCallIdSet, //7 - m_hResponse.CallId = this.CallId; hBuilder.MethodCall(RpcInfo), hBuilder.ResponseSend, //8 - hContext.Send(m_hResponse); "Generated With: " + hBuilder.GetType().Name ); Code = sResult; }
public string MethodCall(RpcMethodInfo hRpc) { string sMethodCall = string.Format("m_hMethod.Invoke(hService, new object[] {{ hContext, {0} }})", hRpc.Method.GetParametersString(false)); if (hRpc.Method.ReturnType == typeof(void)) { sMethodCall = string.Format("{0}; m_hResponse.Encode();", sMethodCall); } else { sMethodCall = string.Format("m_hResponse.Encode(({0}){1});", hRpc.Method.ReturnType.AsKeyword(), sMethodCall); } return sMethodCall; }
/// <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); } }
public void GetMatchingMethod_SimpleMulitParam_DictMatch() { DefaultRequestMatcher matcher = this.GetMatcher(); var parameters = new Dictionary <string, RpcParameterType> { { "a", RpcParameterType.Number }, { "b", RpcParameterType.Boolean }, { "c", RpcParameterType.String }, { "d", RpcParameterType.Object }, { "e", RpcParameterType.Null } }; string methodName = nameof(MethodMatcherController.SimpleMulitParam); var requestSignature = RpcRequestSignature.Create(methodName, parameters); RpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature); Assert.NotNull(methodInfo); MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !; Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo); Assert.Equal(5, methodInfo.Parameters.Length); Assert.False(methodInfo.Parameters[0].IsOptional); Assert.Equal(typeof(int), methodInfo.Parameters[0].RawType); Assert.Equal(RpcParameterType.Number, methodInfo.Parameters[0].Type); Assert.Equal("a", methodInfo.Parameters[0].Name); Assert.False(methodInfo.Parameters[1].IsOptional); Assert.Equal(typeof(bool), methodInfo.Parameters[1].RawType); Assert.Equal(RpcParameterType.Boolean, methodInfo.Parameters[1].Type); Assert.Equal("b", methodInfo.Parameters[1].Name); Assert.False(methodInfo.Parameters[2].IsOptional); Assert.Equal(typeof(string), methodInfo.Parameters[2].RawType); Assert.Equal(RpcParameterType.String, methodInfo.Parameters[2].Type); Assert.Equal("c", methodInfo.Parameters[2].Name); Assert.False(methodInfo.Parameters[3].IsOptional); Assert.Equal(typeof(object), methodInfo.Parameters[3].RawType); Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[3].Type); Assert.Equal("d", methodInfo.Parameters[3].Name); Assert.True(methodInfo.Parameters[4].IsOptional); Assert.Equal(typeof(int?), methodInfo.Parameters[4].RawType); Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[4].Type); Assert.Equal("e", methodInfo.Parameters[4].Name); }
public void GetMatchingMethod_GuidParameter_Match() { string methodName = nameof(MethodMatcherController.GuidTypeMethod); DefaultRequestMatcher matcher = this.GetMatcher(); var requestSignature = RpcRequestSignature.Create(methodName, new[] { RpcParameterType.String }); RpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature); Assert.NotNull(methodInfo); MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !; Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo); Assert.Single(methodInfo.Parameters); Assert.False(methodInfo.Parameters[0].IsOptional); Assert.Equal(typeof(Guid), methodInfo.Parameters[0].RawType); Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[0].Type); Assert.Equal("guid", methodInfo.Parameters[0].Name); }
public string GetEndpoint(RpcMethodInfo invokeInfo) { if (TypeReg.ContainsKey(invokeInfo.MasterType)) { return(TypeReg[invokeInfo.MasterType][0]); } if (AssemblyReg.ContainsKey(invokeInfo.MasterType.Assembly)) { return(AssemblyReg[invokeInfo.MasterType.Assembly][0]); } if (Next == null) { throw new UrlNotConfiguredException(invokeInfo); } else { return(Next.GetEndpoint(invokeInfo)); } }
public void GetMatchingMethod_ListParam_Match() { DefaultRequestMatcher matcher = this.GetMatcher(); RpcParameterType[] parameters = new[] { RpcParameterType.Object }; string methodName = nameof(MethodMatcherController.List); var requestSignature = RpcRequestSignature.Create(methodName, parameters); RpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature); Assert.NotNull(methodInfo); MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !; Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo); Assert.Single(methodInfo.Parameters); Assert.False(methodInfo.Parameters[0].IsOptional); Assert.Equal(typeof(List <string>), methodInfo.Parameters[0].RawType); Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[0].Type); Assert.Equal("values", methodInfo.Parameters[0].Name); }
public ResponseActionCodeGen(IResponseActionBuilder hBuilder, RpcMethodInfo hRpc) { Name = string.Format("Response{0}Action", hRpc.Method.Name); RpcInfo = hRpc; string sResult = string.Format(@" using System; using System.Reflection; using Netbase.Shared; {0} namespace {1} {{ //{7} public class {2} : {3}, IAction {{ private const string m_sMethodName = ""On{5}""; private static MethodInfo m_hMethod; public void Execute(IService hService, ISession hContext) {{ if(m_hMethod == null) {6} {4} }} }} }} ", hBuilder.UsingNamespace(RpcInfo.Service), hBuilder.Namespace(RpcInfo), Name, RpcInfo.Response.Name, hBuilder.MethodInvoke, RpcInfo.Method.Name, hBuilder.MethodInit, "Generated With: " + hBuilder.GetType().Name); Code = sResult; }
public void GetMatchingMethod_CulturallyInvariantComparison() { DefaultRequestMatcher matcher = this.GetMatcher(); RpcParameterType[] parameters = Array.Empty <RpcParameterType>(); string methodName = nameof(MethodMatcherController.IsLunchTime); // Use lowercase version of method name when making request. var methodNameLower = methodName.ToLowerInvariant(); var requestSignature = RpcRequestSignature.Create(methodNameLower, parameters); var previousCulture = System.Globalization.CultureInfo.CurrentCulture; // Switch to a culture that would result in lowercasing 'I' to // U+0131, if not done with invariant culture. System.Globalization.CultureInfo.CurrentCulture = new System.Globalization.CultureInfo("az"); RpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature); Assert.NotNull(methodInfo); MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !; Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo); System.Globalization.CultureInfo.CurrentCulture = previousCulture; }
private DefaultRpcInvoker GetInvoker(MethodInfo?methodInfo, RpcPath?path = null) { var logger = new Mock <ILogger <DefaultRpcInvoker> >(MockBehavior.Loose); var options = new Mock <IOptions <RpcServerConfiguration> >(MockBehavior.Strict); var matcher = new Mock <IRpcRequestMatcher>(MockBehavior.Strict); var accessor = new Mock <IRpcContextAccessor>(MockBehavior.Strict); IRpcContext requestContext = this.GetRouteContext(path); accessor .SetupGet(a => a.Value) .Returns(requestContext); Moq.Language.Flow.ISetup <IRpcRequestMatcher, RpcMethodInfo> matcherSetup = matcher .Setup(m => m.GetMatchingMethod(It.IsAny <RpcRequestSignature>())); if (methodInfo != null) { //TODO better way of getting this for unit tests? RpcMethodInfo method = DefaultRequestMatcher.BuildMethodInfo(methodInfo); matcherSetup.Returns(method); } else { matcherSetup.Throws(new RpcException(RpcErrorCode.MethodNotFound, "Method not found")); } var config = new RpcServerConfiguration(); config.ShowServerExceptions = true; options .SetupGet(o => o.Value) .Returns(config); var authHandler = new Mock <IRpcAuthorizationHandler>(MockBehavior.Strict); authHandler .Setup(h => h.IsAuthorizedAsync(It.IsAny <MethodInfo>())) .Returns(Task.FromResult(true)); return(new DefaultRpcInvoker(logger.Object, options.Object, matcher.Object, accessor.Object, authHandler.Object)); }
private void WriteServerCallbackMethod(RpcMethodInfo hTransportCodeGen, StringBuilder hSb) { string sResult = string.Format(@" public abstract void On{0}(T hContex, {1} hData); ", hTransportCodeGen.Method.Name, "Response" + hTransportCodeGen.Method.Name); hSb.AppendLine(sResult); }
public string MethodToCall(RpcMethodInfo hRpcInfo) { return string.Format("{0}", hRpcInfo.Method.Name); }
public Task <object> Invoke(RpcMethodInfo toCall, object[] param) { return(GetClient(toCall).Invoke(toCall, param)); }
internal string CreateIdString(RpcMethodInfo toCall) { return($"{toCall.ServiceId}.{toCall.Name}-{string.Join("-",toCall.ParamType.Select(p=> p.FullName).ToArray())}"); }
public UrlNotConfiguredException(RpcMethodInfo invokeInfo) : this(invokeInfo.ServiceId) { this.invokeInfo = invokeInfo; }
public RequestCodeGen(RpcMethodInfo hRpcInfo, int iProtocolCounter) { Name = string.Format("Request{0}", hRpcInfo.Method.Name); RpcInfo = hRpcInfo; StringBuilder hPropertyList = new StringBuilder(); hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hPropertyList.AppendFormat("public {0}\t\t{1}\t\t\t{{ get; private set; }}{2}\t", hP.ParameterType.AsKeyword(), hP.Name, Environment.NewLine)); StringBuilder hParamList = new StringBuilder(); hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hParamList.AppendFormat("{0} {1},", hP.ParameterType.AsKeyword(), hP.Name)); if (hParamList.Length > 0) hParamList.Remove(hParamList.Length - 1, 1); StringBuilder hEncodeCalls = new StringBuilder(); hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hEncodeCalls.AppendFormat(@" m_hWriter.Write({0});{1}", hP.Name, Environment.NewLine)); if (hEncodeCalls.Length > 0) hEncodeCalls.Remove(hEncodeCalls.Length - 1, 1); StringBuilder hReadCalls = new StringBuilder(); hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hReadCalls.AppendFormat(@" {0} = hReader.Read{1}();{2}", hP.Name, hP.ParameterType.Name, Environment.NewLine)); if (hReadCalls.Length > 0) hReadCalls.Remove(hReadCalls.Length - 1, 1); string sResult = string.Format(@" using Netbase.Shared; using System; using System.Collections.Generic; using System.IO; using System.Text; namespace {0} {{ [NetbasePacket({1})] public class {2} : Packet {{ {3} public {4}() : base({1}, {5}) {{ }} public void Encode({6}) {{ this.BeginEncode(); {7} this.EndEncode(); }} public override void LoadData(BinaryReader hReader) {{ base.LoadData(hReader); {8} }} }} }}", hRpcInfo.Service.Pair.Client.Namespace, iProtocolCounter, Name, hPropertyList.ToString(), Name, 1024, hParamList, hEncodeCalls, hReadCalls); Code = sResult; }
public string MethodCall(RpcMethodInfo hRpc) { return string.Format("m_hMethod.Invoke(hService, new object[] {{ hContext, {0} }});", hRpc.Method.GetParametersString(false)); }
/// <summary> /// Detects if list of parameters matches the method signature /// </summary> /// <param name="parameterList">Array of parameters for the method</param> /// <returns>True if the method signature matches the parameterList, otherwise False</returns> private bool HasParameterSignature(MethodInfo method, RpcRequest rpcRequest, out RpcMethodInfo rpcMethodInfo) { JToken[] orignialParameterList; if (rpcRequest.Parameters == null) { orignialParameterList = new JToken[0]; } else { switch (rpcRequest.Parameters.Type) { case JTokenType.Object: JsonSerializer jsonSerializer = this.GetJsonSerializer(); Dictionary <string, JToken> parameterMap = rpcRequest.Parameters.ToObject <Dictionary <string, JToken> >(jsonSerializer); bool canParse = this.TryParseParameterList(method, parameterMap, out orignialParameterList); if (!canParse) { rpcMethodInfo = null; return(false); } break; case JTokenType.Array: orignialParameterList = rpcRequest.Parameters.ToArray(); break; default: orignialParameterList = new JToken[0]; break; } } ParameterInfo[] parameterInfoList = method.GetParameters(); if (orignialParameterList.Length > parameterInfoList.Length) { rpcMethodInfo = null; return(false); } object[] correctedParameterList = new object[parameterInfoList.Length]; for (int i = 0; i < orignialParameterList.Length; i++) { ParameterInfo parameterInfo = parameterInfoList[i]; JToken parameter = orignialParameterList[i]; bool isMatch = this.ParameterMatches(parameterInfo, parameter, out object convertedParameter); if (!isMatch) { rpcMethodInfo = null; return(false); } correctedParameterList[i] = convertedParameter; } if (orignialParameterList.Length < parameterInfoList.Length) { //make a new array at the same length with padded 'missing' parameters (if optional) for (int i = orignialParameterList.Length; i < parameterInfoList.Length; i++) { if (!parameterInfoList[i].IsOptional) { rpcMethodInfo = null; return(false); } correctedParameterList[i] = Type.Missing; } } rpcMethodInfo = new RpcMethodInfo(method, correctedParameterList, orignialParameterList); return(true); }
/// <summary> /// Detects if list of parameters matches the method signature /// </summary> /// <param name="parameterList">Array of parameters for the method</param> /// <returns>True if the method signature matches the parameterList, otherwise False</returns> private (bool Matches, RpcMethodInfo MethodInfo) HasParameterSignature(MethodInfo method, RpcRequest rpcRequest) { object[] orignialParameterList; if (!rpcRequest.Parameters.HasValue) { orignialParameterList = new object[0]; } else { switch (rpcRequest.Parameters.Type) { case RpcParametersType.Dictionary: Dictionary <string, object> parameterMap = rpcRequest.Parameters.DictionaryValue; bool canParse = this.TryParseParameterList(method, parameterMap, out orignialParameterList); if (!canParse) { return(false, null); } break; case RpcParametersType.Array: orignialParameterList = rpcRequest.Parameters.ArrayValue; break; default: orignialParameterList = new JToken[0]; break; } } ParameterInfo[] parameterInfoList = method.GetParameters(); if (orignialParameterList.Length > parameterInfoList.Length) { return(false, null); } object[] correctedParameterList = new object[parameterInfoList.Length]; for (int i = 0; i < orignialParameterList.Length; i++) { ParameterInfo parameterInfo = parameterInfoList[i]; object parameter = orignialParameterList[i]; bool isMatch = this.ParameterMatches(parameterInfo, parameter, out object convertedParameter); if (!isMatch) { return(false, null); } correctedParameterList[i] = convertedParameter; } if (orignialParameterList.Length < parameterInfoList.Length) { //make a new array at the same length with padded 'missing' parameters (if optional) for (int i = orignialParameterList.Length; i < parameterInfoList.Length; i++) { if (!parameterInfoList[i].IsOptional) { return(false, null); } correctedParameterList[i] = Type.Missing; } } var rpcMethodInfo = new RpcMethodInfo(method, correctedParameterList, orignialParameterList); return(true, rpcMethodInfo); }
public string Namespace(RpcMethodInfo hRpcInfo) { return string.Format("{0}", hRpcInfo.Service.Pair.Client.Namespace); }
public string Namespace(RpcMethodInfo RpcInfo) { return RpcInfo.Service.Pair.Server.Namespace; }
/// <summary> /// Finds the matching Rpc method for the current request /// </summary> /// <param name="path">Rpc route for the current request</param> /// <param name="request">Current Rpc request</param> /// <param name="parameterList">Parameter list parsed from the request</param> /// <param name="serviceProvider">(Optional)IoC Container for rpc method controllers</param> /// <returns>The matching Rpc method to the current request</returns> private RpcMethodInfo GetMatchingMethod(RpcPath path, RpcRequest request, IRpcRouteProvider routeProvider, IServiceProvider serviceProvider) { if (request == null) { throw new ArgumentNullException(nameof(request)); } this.logger?.LogDebug($"Attempting to match Rpc request to a method '{request.Method}'"); List <MethodInfo> allMethods = this.GetRpcMethods(path, routeProvider); //Case insenstive check for hybrid approach. Will check for case sensitive if there is ambiguity var requestMethodName = this.convertSnakeCaseToCamelCase ? this.ConvertSnakeCaseToCamelCase(request.Method) : request.Method; List <MethodInfo> methodsWithSameName = allMethods .Where(m => string.Equals(m.Name, requestMethodName, StringComparison.OrdinalIgnoreCase)) .ToList(); var potentialMatches = new List <RpcMethodInfo>(); foreach (MethodInfo method in methodsWithSameName) { (bool isMatch, RpcMethodInfo methodInfo) = this.HasParameterSignature(method, request); if (isMatch) { potentialMatches.Add(methodInfo); } } if (potentialMatches.Count > 1) { //Try to remove ambiguity with 'perfect matching' (usually optional params and types) List <RpcMethodInfo> exactMatches = potentialMatches .Where(p => p.HasExactParameterMatch()) .ToList(); if (exactMatches.Any()) { potentialMatches = exactMatches; } if (potentialMatches.Count > 1) { //Try to remove ambiguity with case sensitive check potentialMatches = potentialMatches .Where(m => string.Equals(m.Method.Name, requestMethodName, 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(); } } } RpcMethodInfo rpcMethod = null; if (potentialMatches.Count == 1) { rpcMethod = potentialMatches.First(); } if (rpcMethod == null) { //Log diagnostics string methodsString = string.Join(", ", allMethods.Select(m => m.Name)); this.logger?.LogTrace("Methods in route: " + methodsString); var methodInfoList = new List <string>(); foreach (MethodInfo matchedMethod in methodsWithSameName) { var parameterTypeList = new List <string>(); foreach (ParameterInfo parameterInfo in matchedMethod.GetParameters()) { string parameterType = parameterInfo.Name + ": " + parameterInfo.ParameterType.Name; if (parameterInfo.IsOptional) { parameterType += "(Optional)"; } parameterTypeList.Add(parameterType); } string parameterString = string.Join(", ", parameterTypeList); methodInfoList.Add($"{{Name: '{matchedMethod.Name}', Parameters: [{parameterString}]}}"); } this.logger?.LogTrace("Methods that matched the same name: " + string.Join(", ", methodInfoList)); this.logger?.LogError("No methods matched request."); throw new RpcMethodNotFoundException(); } this.logger?.LogDebug("Request was matched to a method"); return(rpcMethod); }
/// <summary> /// Call the incoming Rpc request method and gives the appropriate response /// </summary> /// <param name="request">Rpc request</param> /// <param name="path">Rpc path that applies to the current request</param> /// <param name="httpContext">The context of the current http request</param> /// <returns>An Rpc response for the request</returns> public async Task <RpcResponse> InvokeRequestAsync(RpcRequest request, RpcPath path, IRouteContext routeContext) { try { if (request == null) { throw new ArgumentNullException(nameof(request)); } } catch (ArgumentNullException ex) // Dont want to throw any exceptions when doing async requests { return(this.GetUnknownExceptionReponse(request, ex)); } this.logger?.LogDebug($"Invoking request with id '{request.Id}'"); RpcResponse rpcResponse; try { if (!string.Equals(request.JsonRpcVersion, JsonRpcContants.JsonRpcVersion)) { throw new RpcInvalidRequestException($"Request must be jsonrpc version '{JsonRpcContants.JsonRpcVersion}'"); } RpcMethodInfo rpcMethod = this.GetMatchingMethod(path, request, routeContext.RouteProvider, routeContext.RequestServices); bool isAuthorized = await this.IsAuthorizedAsync(rpcMethod.Method, routeContext); if (isAuthorized) { object result = null; if (request.Id.HasValue) { this.logger?.LogDebug($"Attempting to invoke method '{request.Method}'"); result = await this.InvokeAsync(rpcMethod, path); this.logger?.LogDebug($"Finished invoking method '{request.Method}'"); } else { this.logger?.LogDebug($"Attempting to invoke notification '{request.Method}'"); this.FireAndForget(async() => await this.InvokeAsync(rpcMethod, path)); } JsonSerializer jsonSerializer = this.GetJsonSerializer(); if (result is IRpcMethodResult) { this.logger?.LogTrace($"Result is {nameof(IRpcMethodResult)}."); rpcResponse = ((IRpcMethodResult)result).ToRpcResponse(request.Id, obj => JToken.FromObject(obj, jsonSerializer)); } else { this.logger?.LogTrace($"Result is plain object."); JToken resultJToken = result != null?JToken.FromObject(result, jsonSerializer) : null; rpcResponse = new RpcResponse(request.Id, resultJToken); } } else { var authError = new RpcError(RpcErrorCode.InvalidRequest, "Unauthorized"); rpcResponse = new RpcResponse(request.Id, authError); } } catch (RpcException ex) { this.logger?.LogException(ex, "An Rpc error occurred. Returning an Rpc error response"); RpcError error = new RpcError(ex, this.serverConfig.Value.ShowServerExceptions); rpcResponse = new RpcResponse(request.Id, error); } catch (Exception ex) { rpcResponse = this.GetUnknownExceptionReponse(request, ex); } if (request.Id.HasValue) { this.logger?.LogDebug($"Finished request with id: {request.Id}"); //Only give a response if there is an id return(rpcResponse); } this.logger?.LogDebug($"Finished request with no id."); return(rpcResponse); }