예제 #1
0
        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);
        }
예제 #2
0
        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);
            }
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }