public RpcMethodInfo GetMatchingMethod(RpcRequestSignature requestSignature) { this.logger.AttemptingToMatchMethod(new string(requestSignature.GetMethodName().Span)); IReadOnlyList <MethodInfo> methods = this.methodProvider.Get(); if (methods == null || !methods.Any()) { throw new RpcException(RpcErrorCode.MethodNotFound, $"No methods found for route"); } RpcMethodInfo[] compiledMethods = ArrayPool <RpcMethodInfo> .Shared.Rent(methods.Count); Span <RpcMethodInfo> matches; try { this.FillRpcMethodInfos(methods, compiledMethods); matches = this.FilterAndBuildMethodInfoByRequest(compiledMethods.AsMemory(0, methods.Count), requestSignature); } finally { ArrayPool <RpcMethodInfo> .Shared.Return(compiledMethods, clearArray : true); } if (matches.Length == 1) { this.logger.RequestMatchedMethod(); return(matches[0]); } string errorMessage; if (matches.Length > 1) { var methodInfoList = new List <string>(); foreach (RpcMethodInfo matchedMethod in matches) { var parameterTypeList = new List <string>(); foreach (ParameterInfo parameterInfo in matchedMethod.MethodInfo.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.MethodInfo.Name}', Parameters: [{parameterString}]}}"); } errorMessage = "More than one method matched the rpc request. Unable to invoke due to ambiguity. Methods that matched the same name: " + string.Join(", ", methodInfoList); } else { //Log diagnostics this.logger.MethodsInRoute(methods); errorMessage = "No methods matched request."; } throw new RpcException(RpcErrorCode.MethodNotFound, errorMessage); }
private IRpcMethodInfo[] GetMatchingMethods(RpcRequestSignature requestSignature, IReadOnlyList <IRpcMethodInfo> methods) { IRpcMethodInfo[] methodsWithSameName = ArrayPool <IRpcMethodInfo> .Shared.Rent(methods.Count); try { //Case insenstive check for hybrid approach. Will check for case sensitive if there is ambiguity int methodsWithSameNameCount = 0; for (int i = 0; i < methods.Count; i++) { IRpcMethodInfo methodInfo = methods[i]; if (RpcUtil.NamesMatch(methodInfo.Name.AsSpan(), requestSignature.GetMethodName().Span)) { methodsWithSameName[methodsWithSameNameCount++] = methodInfo; } } if (methodsWithSameNameCount < 1) { return(Array.Empty <IRpcMethodInfo>()); } return(this.FilterBySimilarParams(requestSignature, methodsWithSameName.AsSpan(0, methodsWithSameNameCount))); } finally { ArrayPool <IRpcMethodInfo> .Shared.Return(methodsWithSameName, clearArray : false); } }
private IRpcMethodInfo[] FilterMatchesByCaseSensitiveMethod(RpcRequestSignature requestSignature, Span <IRpcMethodInfo> matches) { //Try to remove ambiguity with case sensitive check IRpcMethodInfo[] caseSensitiveMatches = ArrayPool <IRpcMethodInfo> .Shared.Rent(matches.Length); try { int caseSensitiveCount = 0; for (int i = 0; i < matches.Length; i++) { IRpcMethodInfo m = matches[i]; Memory <char> requestMethodName = requestSignature.GetMethodName(); if (m.Name.Length == requestMethodName.Length) { if (!RpcUtil.NamesMatch(m.Name.AsSpan(), requestMethodName.Span)) { //TODO do we care about the case where 2+ parameters have very similar names and types? continue; } caseSensitiveMatches[caseSensitiveCount++] = m; } } return(caseSensitiveMatches.AsSpan(0, caseSensitiveCount).ToArray()); } finally { ArrayPool <IRpcMethodInfo> .Shared.Return(caseSensitiveMatches, clearArray : false); } }
public IRpcMethodInfo GetMatchingMethod(RpcRequestSignature requestSignature) { this.logger.AttemptingToMatchMethod(new string(requestSignature.GetMethodName().Span)); RpcContext context = this.contextAccessor.Get(); IReadOnlyList <IRpcMethodInfo>?methods = this.methodProvider.GetByPath(context.Path); if (methods == null || !methods.Any()) { throw new RpcException(RpcErrorCode.MethodNotFound, $"No methods found for route"); } Span <IRpcMethodInfo> matches = this.FilterAndBuildMethodInfoByRequest(methods, requestSignature); if (matches.Length == 1) { this.logger.RequestMatchedMethod(); return(matches[0]); } string errorMessage; if (matches.Length > 1) { var methodInfoList = new List <string>(); foreach (IRpcMethodInfo matchedMethod in matches) { var parameterTypeList = new List <string>(); foreach (IRpcParameterInfo parameterInfo in matchedMethod.Parameters) { string parameterType = parameterInfo.Name + ": " + parameterInfo.Type; if (parameterInfo.IsOptional) { parameterType += "(Optional)"; } parameterTypeList.Add(parameterType); } string parameterString = string.Join(", ", parameterTypeList); methodInfoList.Add($"{{Name: '{matchedMethod.Name}', Parameters: [{parameterString}]}}"); } errorMessage = "More than one method matched the rpc request. Unable to invoke due to ambiguity. Methods that matched the same name: " + string.Join(", ", methodInfoList); } else { //Log diagnostics this.logger.MethodsInRoute(methods); errorMessage = "No methods matched request."; } throw new RpcException(RpcErrorCode.MethodNotFound, errorMessage); }