예제 #1
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);
            }
        }
예제 #2
0
        public string GetSummaryForMethod(IRpcMethodInfo methodInfo)
        {
            var methodNode  = this.xpathNavigator.SelectSingleNode($"/doc/members/member[@name='{methodInfo.Name}']");
            var summaryNode = methodNode?.SelectSingleNode("summary");

            return(summaryNode != null?XmlCommentsTextHelper.Humanize(summaryNode.InnerXml) : string.Empty);
        }
예제 #3
0
        public RpcEndpointBuilder AddMethod(MethodInfo methodInfo, RpcPath?path = null)
        {
            IRpcMethodInfo rpcMethodInfo = DefaultRpcMethodInfo.FromMethodInfo(methodInfo);

            this.Add(path, rpcMethodInfo);
            return(this);
        }
예제 #4
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);
            }
        }
예제 #5
0
        private IRpcMethodInfo[] FilterBySimilarParams(RpcRequestSignature requestSignature, Span <IRpcMethodInfo> methodsWithSameName)
        {
            IRpcMethodInfo[] potentialMatches = ArrayPool <IRpcMethodInfo> .Shared.Rent(methodsWithSameName.Length);

            try
            {
                int potentialMatchCount = 0;
                for (int i = 0; i < methodsWithSameName.Length; i++)
                {
                    IRpcMethodInfo m = methodsWithSameName[i];

                    bool isMatch = this.ParametersMatch(requestSignature, m.Parameters);
                    if (isMatch)
                    {
                        potentialMatches[potentialMatchCount++] = m;
                    }
                }

                if (potentialMatchCount <= 1)
                {
                    return(potentialMatches.AsSpan(0, potentialMatchCount).ToArray());
                }
                return(this.FilterMatchesByCaseSensitiveMethod(requestSignature, potentialMatches.AsSpan(0, potentialMatchCount)));
            }
            finally
            {
                ArrayPool <IRpcMethodInfo> .Shared.Return(potentialMatches, clearArray : false);
            }
        }
        public async Task <bool> IsAuthorizedAsync(IRpcMethodInfo methodInfo)
        {
            if (methodInfo.AuthorizeDataList.Any())
            {
                if (methodInfo.AllowAnonymous)
                {
                    this.logger.SkippingAuth();
                }
                else
                {
                    this.logger.RunningAuth();
                    AuthorizationResult authResult = await this.CheckAuthorize(methodInfo.AuthorizeDataList);

                    if (authResult.Succeeded)
                    {
                        this.logger.AuthSuccessful();
                    }
                    else
                    {
                        this.logger.AuthFailed();
                        return(false);
                    }
                }
            }
            else
            {
                this.logger.NoConfiguredAuth();
            }
            return(true);
        }
예제 #7
0
        private OpenApiOperation GetOpenApiOperation(string key, IRpcMethodInfo methodInfo, SchemaRepository schemaRepository)
        {
            string methodAnnotation = this.xmlDocumentationService.GetSummaryForMethod(methodInfo);
            Type   trueReturnType   = this.GetReturnType(methodInfo.RawReturnType);

            return(new OpenApiOperation()
            {
                Tags = new List <OpenApiTag>(),
                Summary = methodAnnotation,
                RequestBody = this.GetOpenApiRequestBody(key, methodInfo, schemaRepository),
                Responses = this.GetOpenApiResponses(key, trueReturnType, schemaRepository)
            });
        }
예제 #8
0
        public string GetMethodParameterExample(IRpcMethodInfo methodInfo, IRpcParameterInfo parameterInfo)
        {
            var paramNode = this.xpathNavigator.SelectSingleNode(
                $"/doc/members/member[@name='{methodInfo.Name}']/param[@name='{parameterInfo.Name}']");

            if (paramNode == null)
            {
                return(string.Empty);
            }
            var example = paramNode.GetAttribute("example", "");

            return(example);
        }
예제 #9
0
 private OpenApiRequestBody GetOpenApiRequestBody(string key, IRpcMethodInfo methodInfo,
                                                  SchemaRepository schemaRepository)
 {
     return(new OpenApiRequestBody()
     {
         Content = new Dictionary <string, OpenApiMediaType>()
         {
             ["application/json"] = new OpenApiMediaType()
             {
                 Schema = this.GetBodyParamsSchema(key, schemaRepository, methodInfo)
             }
         }
     });
 }
예제 #10
0
        public void GetMatchingMethod_GuidParameter_Match()
        {
            string methodName = nameof(MethodMatcherController.GuidTypeMethod);

            DefaultRequestMatcher matcher   = this.GetMatcher(path: typeof(MethodMatcherController).GetTypeInfo().Name);
            var            requestSignature = RpcRequestSignature.Create(methodName, new[] { RpcParameterType.String });
            IRpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);

            Assert.NotNull(methodInfo);
            Assert.Equal(methodName, methodInfo.Name);
            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);
        }
예제 #11
0
        public void GetMatchingMethod_WithRpcRoute()
        {
            string methodName = nameof(MethodMatcherController.GuidTypeMethod);
            RpcRequestSignature requestSignature = RpcRequestSignature.Create(methodName, new[] { RpcParameterType.String });

            DefaultRequestMatcher path1Matcher = this.GetMatcher(path: typeof(MethodMatcherController).GetTypeInfo().Name);
            IRpcMethodInfo        path1Match   = path1Matcher.GetMatchingMethod(requestSignature);

            Assert.NotNull(path1Match);


            DefaultRequestMatcher path2Matcher = this.GetMatcher(path: typeof(MethodMatcherDuplicatesController).GetTypeInfo().Name);
            IRpcMethodInfo        path2Match   = path2Matcher.GetMatchingMethod(requestSignature);

            Assert.NotNull(path2Match);
            Assert.NotSame(path1Match, path2Match);
        }
예제 #12
0
        public void GetMatchingMethod_SimpleMulitParam_DictMatch()
        {
            DefaultRequestMatcher matcher = this.GetMatcher(path: typeof(MethodMatcherController).GetTypeInfo().Name);

            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);
            IRpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            Assert.Equal(methodName, methodInfo.Name);
            Assert.Equal(5, methodInfo.Parameters.Count);

            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);
        }
예제 #13
0
        public void GetMatchingMethod_ListParam_Match()
        {
            DefaultRequestMatcher matcher = this.GetMatcher(path: typeof(MethodMatcherController).GetTypeInfo().Name);

            RpcParameterType[] parameters   = new[] { RpcParameterType.Object };
            string             methodName   = nameof(MethodMatcherController.List);
            var            requestSignature = RpcRequestSignature.Create(methodName, parameters);
            IRpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            Assert.Equal(methodName, methodInfo.Name);
            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);
        }
예제 #14
0
        public void GetMatchingMethod_CulturallyInvariantComparison()
        {
            DefaultRequestMatcher matcher = this.GetMatcher(path: typeof(MethodMatcherController).GetTypeInfo().Name);

            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");
            IRpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature);

            Assert.NotNull(methodInfo);
            Assert.Equal(methodName, methodInfo.Name);
            System.Globalization.CultureInfo.CurrentCulture = previousCulture;
        }
예제 #15
0
        private void Add(RpcPath?path, IRpcMethodInfo methodInfo)
        {
            List <IRpcMethodInfo> methods;

            if (path == null)
            {
                methods = this.baseMethods;
            }
            else
            {
                if (!this.methods.TryGetValue(path, out List <IRpcMethodInfo>?m))
                {
                    methods = this.methods[path] = new List <IRpcMethodInfo>();
                }
                else
                {
                    methods = m !;
                }
            }
            methods.Add(methodInfo);
        }
예제 #16
0
        public void GetMatchingMethod_ListParam_Match_Snake_Case(string parameterNameCase)
        {
            DefaultRequestMatcher matcher = this.GetMatcher(path: typeof(MethodMatcherController).GetTypeInfo().Name);

            IEnumerable <KeyValuePair <string, RpcParameterType> > parameters = new[]
            {
                new KeyValuePair <string, RpcParameterType>(parameterNameCase, RpcParameterType.String)
            };

            string         methodName       = nameof(MethodMatcherController.SnakeCaseParams);
            var            requestSignature = RpcRequestSignature.Create(methodName, parameters);
            IRpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            Assert.Equal(methodName, methodInfo.Name);
            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));
        }
예제 #17
0
        private OpenApiSchema GetBodyParamsSchema(string key, SchemaRepository schemaRepository, IRpcMethodInfo methodInfo)
        {
            OpenApiSchema paramsObjectSchema = this.GetOpenApiEmptyObject();

            foreach (IRpcParameterInfo parameterInfo in methodInfo.Parameters)
            {
                string        name   = this.namePolicy.ConvertName(parameterInfo.Name);
                OpenApiSchema schema = this.schemaGenerator.GenerateSchema(parameterInfo.RawType, schemaRepository);
                paramsObjectSchema.Properties.Add(name, schema);
            }

            paramsObjectSchema = schemaRepository.AddDefinition($"{key}", paramsObjectSchema);

            var requestSchema = this.GetOpenApiEmptyObject();

            requestSchema.Properties.Add("id", this.schemaGenerator.GenerateSchema(typeof(string), schemaRepository));
            requestSchema.Properties.Add("jsonrpc", this.schemaGenerator.GenerateSchema(typeof(string), schemaRepository));
            requestSchema.Properties.Add("method", this.schemaGenerator.GenerateSchema(typeof(string), schemaRepository));
            requestSchema.Properties.Add("params", paramsObjectSchema);

            requestSchema = schemaRepository.AddDefinition($"request_{key}", requestSchema);

            this.RewriteJrpcAttributesExamples(requestSchema, schemaRepository, this.namePolicy.ConvertName(methodInfo.Name));

            return(requestSchema);
        }
예제 #18
0
 public RpcEndpointBuilder AddMethod(IRpcMethodInfo methodInfo, RpcPath?path = null)
 {
     this.Add(path, methodInfo);
     return(this);
 }
예제 #19
0
 public UniqueMethod(string uniqueUrl, IRpcMethodInfo info)
 {
     this.UniqueUrl = uniqueUrl;
     this.Info      = info;
 }