Beispiel #1
0
    public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate()
    {
        // Arrange
        var endpoints    = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
        var scores       = new int[] { 0, 0, 1 };
        var candidateSet = CreateCandidateSet(endpoints, scores);

        candidateSet.SetValidity(0, false);
        candidateSet.SetValidity(1, true);
        candidateSet.SetValidity(2, true);

        var httpContext = CreateContext();
        var selector    = CreateSelector();

        // Act
        await selector.SelectAsync(httpContext, candidateSet);

        // Assert
        Assert.Same(endpoints[1], httpContext.GetEndpoint());
    }
Beispiel #2
0
        private void AddRequiredLiteralValue(RouteEndpoint endpoint, List <DfaNode> nextParents, DfaNode parent, RoutePatternParameterPart parameterPart, object requiredValue)
        {
            if (endpoint.RoutePattern.ParameterPolicies.TryGetValue(parameterPart.Name, out var parameterPolicyReferences))
            {
                for (var k = 0; k < parameterPolicyReferences.Count; k++)
                {
                    var reference       = parameterPolicyReferences[k];
                    var parameterPolicy = _parameterPolicyFactory.Create(parameterPart, reference);
                    if (parameterPolicy is IOutboundParameterTransformer parameterTransformer)
                    {
                        requiredValue = parameterTransformer.TransformOutbound(requiredValue);
                        break;
                    }
                }
            }

            var literalValue = requiredValue?.ToString() ?? throw new InvalidOperationException($"Required value for literal '{parameterPart.Name}' must evaluate to a non-null string.");

            AddLiteralNode(_includeLabel, nextParents, parent, literalValue);
        }
Beispiel #3
0
        public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate()
        {
            // Arrange
            var endpoints    = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
            var scores       = new int[] { 0, 0, 1 };
            var candidateSet = CreateCandidateSet(endpoints, scores);

            candidateSet[0].IsValidCandidate = false;
            candidateSet[1].IsValidCandidate = true;
            candidateSet[2].IsValidCandidate = true;

            var(httpContext, feature) = CreateContext();
            var selector = CreateSelector();

            // Act
            await selector.SelectAsync(httpContext, feature, candidateSet);

            // Assert
            Assert.Same(endpoints[1], feature.Endpoint);
        }
Beispiel #4
0
        private bool MatchesEndpoint(string absPath)
        {
            // Borrowed and modified from https://stackoverflow.com/a/59550580

            // Return a collection of Microsoft.AspNetCore.Http.Endpoint instances.
            IEnumerable <RouteEndpoint> routeEndpoints = _endpointDataSource?.Endpoints
                                                         .OfType <RouteEndpoint>()
                                                         .Where(x =>
            {
                // We don't want to include dynamic endpoints in this check since we would have no idea if that
                // matches since they will probably match everything.
                bool isDynamic = x.Metadata.OfType <IDynamicEndpointMetadata>().Any(x => x.IsDynamic);
                if (isDynamic)
                {
                    return(false);
                }

                // filter out matched endpoints that are suppressed
                var isSuppressed = x.Metadata.OfType <ISuppressMatchingMetadata>().FirstOrDefault()?.SuppressMatching == true;
                if (isSuppressed)
                {
                    return(false);
                }

                return(true);
            });

            var routeValues = new RouteValueDictionary();

            // To get the matchedEndpoint of the provide url
            RouteEndpoint matchedEndpoint = routeEndpoints?
                                            .Where(e => e.RoutePattern.RawText != null)
                                            .Where(e => new TemplateMatcher(
                                                       TemplateParser.Parse(e.RoutePattern.RawText),
                                                       new RouteValueDictionary())
                                                   .TryMatch(absPath, routeValues))
                                            .OrderBy(c => c.Order)
                                            .FirstOrDefault();

            return(matchedEndpoint != null);
        }
Beispiel #5
0
        public async Task Match_Regression_1867_DefaultBehavior(string path, int endpointIndex)
        {
            var endpoints = new RouteEndpoint[]
            {
                EndpointFactory.CreateRouteEndpoint(
                    "{firstName}/{lastName}",
                    order: 0,
                    defaults: new { controller = "TestRoute", action = "Index", }),

                EndpointFactory.CreateRouteEndpoint(
                    "middleware/{**_}",
                    order: 0),
            };

            var expected = endpointIndex switch
            {
                -1 => null,
                _ => endpoints[endpointIndex],
            };

            var matcher     = CreateMatcher(useCorrectCatchAllBehavior: default, endpoints);
Beispiel #6
0
        public void IsPartOfRouteTemplate_ReturnsCorrect_ForGivenPart(string part, bool expect)
        {
            // Arrange
            RouteEndpoint endpoint = new RouteEndpoint(
                c => Task.CompletedTask,
                RoutePatternFactory.Parse("odata/customers/{key}/Name"),
                0,
                EndpointMetadataCollection.Empty,
                "test");

            ODataTemplateTranslateContext translateContext = new ODataTemplateTranslateContext
            {
                Endpoint = endpoint
            };

            // Act
            bool actual = translateContext.IsPartOfRouteTemplate(part);

            // Assert
            Assert.Equal(expect, actual);
        }
        public void Matcher_Ignores_SuppressedEndpoint()
        {
            // Arrange
            var dataSource = new DynamicEndpointDataSource();
            var endpoint   = new RouteEndpoint(
                TestConstants.EmptyRequestDelegate,
                RoutePatternFactory.Parse("/"),
                0,
                new EndpointMetadataCollection(new SuppressMatchingMetadata()),
                "test");

            dataSource.AddEndpoint(endpoint);

            // Act
            var matcher = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create);

            // Assert
            var inner = Assert.IsType <TestMatcher>(matcher.CurrentMatcher);

            Assert.Empty(inner.Endpoints);
        }
Beispiel #8
0
        public void TryTranslateKeySegmentTemplate_ThrowsODataException_ForInvalidKey()
        {
            // Arrange
            EdmModel              model        = new EdmModel();
            EdmEntityType         customerType = new EdmEntityType("NS", "Customer");
            EdmStructuralProperty idProperty   = customerType.AddStructuralProperty("customerId", EdmPrimitiveTypeKind.Int32);

            customerType.AddKeys(idProperty);
            model.AddElement(customerType);
            EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
            EdmEntitySet       customers = container.AddEntitySet("Customers", customerType);

            model.AddElement(container);
            RouteValueDictionary         routeValueDictionary = new RouteValueDictionary(new { key = "abc12" });
            IDictionary <string, string> keys = new Dictionary <string, string>
            {
                { "customerId", "{key}" }
            };
            KeySegmentTemplate template = new KeySegmentTemplate(keys, customerType, customers);

            RouteEndpoint endpoint = new RouteEndpoint(
                c => Task.CompletedTask,
                RoutePatternFactory.Parse("odata/customers/{key}/Name"),
                0,
                EndpointMetadataCollection.Empty,
                "test");

            ODataTemplateTranslateContext context = new ODataTemplateTranslateContext
            {
                RouteValues = routeValueDictionary,
                Model       = model,
                Endpoint    = endpoint
            };

            // Act
            Action test = () => template.TryTranslate(context);

            // Assert
            ExceptionAssert.Throws <ODataException>(test, "The key value (abc12) from request is not valid. The key value should be format of type 'Edm.Int32'.");
        }
        private void MapControllerActions(Type type)
        {
            foreach (MethodInfo method in type.GetMethods())
            {
                if (type.IsAbstract || type.IsNotPublic)
                {
                    continue;
                }

                if (method.ReturnType.Equals(typeof(IActionResult)))
                {
                    var controller = type.Name.Replace("Controller", string.Empty).ToLower();
                    var action     = method.Name.ToLower();
                    var uri        = $"{controller}/{action}";

                    var requestDelegate = _controllerFactory.CreateRequestDelegate(type, method);
                    var endpoint        = new RouteEndpoint(requestDelegate, uri, null, $"/{uri}");

                    _endpoints.Add(uri, endpoint);
                }
            }
        }
        public IEnumerable <Endpoint> FindEndpoints(RouteValuesAddress address)
        {
            if (address.AmbientValues == null || address.ExplicitValues == null)
            {
                return(Enumerable.Empty <Endpoint>());
            }

            var homeRoute = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult().HomeRoute;

            if (Match(homeRoute, address.ExplicitValues))
            {
                var routeValues = new RouteValueDictionary(address.ExplicitValues);

                if (address.ExplicitValues.Count > homeRoute.Count)
                {
                    foreach (var entry in address.ExplicitValues)
                    {
                        if (!homeRoute.ContainsKey(entry.Key))
                        {
                            routeValues.Remove(entry.Key);
                        }
                    }
                }

                var endpoint = new RouteEndpoint
                               (
                    c => null,
                    RoutePatternFactory.Parse(String.Empty, routeValues, null),
                    0,
                    null,
                    null
                               );

                return(new[] { endpoint });
            }

            return(Enumerable.Empty <Endpoint>());
        }
Beispiel #11
0
        public void Setup()
        {
            Endpoints    = new RouteEndpoint[10];
            Endpoints[0] = CreateEndpoint("/product", "GET");
            Endpoints[1] = CreateEndpoint("/product/{id}", "GET");

            Endpoints[2] = CreateEndpoint("/account", "GET");
            Endpoints[3] = CreateEndpoint("/account/{id}");
            Endpoints[4] = CreateEndpoint("/account/{id}", "POST");
            Endpoints[5] = CreateEndpoint("/account/{id}", "UPDATE");

            Endpoints[6] = CreateEndpoint("/v2/account", "GET");
            Endpoints[7] = CreateEndpoint("/v2/account/{id}");
            Endpoints[8] = CreateEndpoint("/v2/account/{id}", "POST");
            Endpoints[9] = CreateEndpoint("/v2/account/{id}", "UPDATE");

            // Define an unordered mixture of policies that implement INodeBuilderPolicy,
            // IEndpointComparerPolicy and/or IEndpointSelectorPolicy
            _policies = new List <MatcherPolicy>()
            {
                CreateNodeBuilderPolicy(4),
                CreateUberPolicy(2),
                CreateNodeBuilderPolicy(3),
                CreateEndpointComparerPolicy(5),
                CreateNodeBuilderPolicy(1),
                CreateEndpointSelectorPolicy(9),
                CreateEndpointComparerPolicy(7),
                CreateNodeBuilderPolicy(6),
                CreateEndpointSelectorPolicy(10),
                CreateUberPolicy(12),
                CreateEndpointComparerPolicy(11)
            };
            _loggerFactory          = NullLoggerFactory.Instance;
            _selector               = new DefaultEndpointSelector();
            _parameterPolicyFactory = new DefaultParameterPolicyFactory(Options.Create(new RouteOptions()), new TestServiceProvider());

            _services = CreateServices();
        }
        public void Matcher_Reinitializes_WhenDataSourceChanges()
        {
            // Arrange
            var dataSource = new DynamicEndpointDataSource();
            var matcher    = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create);

            var endpoint = new RouteEndpoint(
                TestConstants.EmptyRequestDelegate,
                RoutePatternFactory.Parse("a/b/c"),
                0,
                EndpointMetadataCollection.Empty,
                "test");

            // Act
            dataSource.AddEndpoint(endpoint);

            // Assert
            var inner = Assert.IsType <TestMatcher>(matcher.CurrentMatcher);

            Assert.Collection(
                inner.Endpoints,
                e => Assert.Same(endpoint, e));
        }
Beispiel #13
0
        public static ApiDescription?TryCreateApiDescription(RouteEndpoint endpoint)
        {
            var metadata = endpoint.Metadata.GetMetadata <GrpcMethodMetadata>();

            if (metadata == null)
            {
                return(null);
            }

            var marker = FindServiceModelGrpcMarker(endpoint.Metadata);

            if (marker == null)
            {
                return(null);
            }

            var operation = new OperationDescription(
                metadata.Method.ServiceName,
                metadata.Method.Name,
                new MessageAssembler(marker.ContractMethodDefinition));

            return(CreateApiDescription(endpoint, metadata, operation));
        }
        public async Task SelectAsync_MultipleValidCandidatesInGroup_ReportsAmbiguity()
        {
            // Arrange
            var endpoints    = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
            var scores       = new int[] { 0, 1, 1 };
            var candidateSet = CreateCandidateSet(endpoints, scores);

            candidateSet.SetValidity(0, false);
            candidateSet.SetValidity(1, true);
            candidateSet.SetValidity(2, true);

            var httpContext = CreateContext();
            var selector    = CreateSelector();

            // Act
            var ex = await Assert.ThrowsAsync <AmbiguousMatchException>(() => selector.SelectAsync(httpContext, candidateSet));

            // Assert
            Assert.Equal(
                @"The request matched multiple endpoints. Matches: " + Environment.NewLine + Environment.NewLine +
                "test: /test2" + Environment.NewLine + "test: /test3", ex.Message);
            Assert.Null(httpContext.GetEndpoint());
        }
Beispiel #15
0
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                       auth_handler_requirement requirement)
        {
            //if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&
            //                                c.Issuer == "http://contoso.com"))
            //{
            //TODO: Use the following if targeting a version of
            //.NET Framework older than 4.6:
            //      return Task.FromResult(0);
            // return Task.CompletedTask;


            RouteEndpoint endpoint  = (RouteEndpoint)context.Resource;
            var           apistring = endpoint.RoutePattern.RawText;
            //context.Succeed(requirement);
            var a = requirement._iAuth.GetRights(int.Parse(context.User.Claims.First(i => i.Type == "userID").Value)).Result;

            if (a.Where(x => x.api == apistring).Count() > 0)
            {
                context.Succeed(requirement); // Basically check if the user has that specific right.
            }
            return(Task.CompletedTask);
        }
Beispiel #16
0
        /// <summary>
        /// Checks whether the endpoint is matched the relative uri specified int the request info.
        /// </summary>
        /// <param name="routeEndpoint">The route endpoint.</param>
        /// <param name="requestInfo">The request information.</param>
        /// <param name="routeValueDictionary">The route value dictionary.</param>
        /// <returns>
        /// Whether the endpoint matches the request info relative uri.
        /// </returns>
        private static EndpointMatchResult EndpointMatches(RouteEndpoint routeEndpoint, RequestInfo requestInfo, out RouteValueDictionary routeValueDictionary)
        {
            if (!_templateMatcherCache.TryGetValue(routeEndpoint.RoutePattern.RawText, out TemplateMatcher templateMatcher))
            {
                RouteTemplate template = TemplateParser.Parse(routeEndpoint.RoutePattern.RawText);
                templateMatcher = new TemplateMatcher(template, GetDefaultRouteValues(template));
                _templateMatcherCache.TryAdd(routeEndpoint.RoutePattern.RawText, templateMatcher);
            }

            routeValueDictionary = new RouteValueDictionary();
            if (templateMatcher.TryMatch(new PathString(requestInfo.RelativeUri), routeValueDictionary))
            {
                // Check if the HTTP method matches
                string requestHttpMethod = requestInfo.Method.ToLower();

                HttpMethodMetadata httpMethodMetadata = routeEndpoint.Metadata.GetMetadata <HttpMethodMetadata>();
                if (httpMethodMetadata == null && requestHttpMethod != HttpMethod.Get.ToString().ToLower())
                {                 // Assume get if no metadata is found
                    return(EndpointMatchResult.NoMatch);
                }
                if (!httpMethodMetadata.HttpMethods.Any(httpMethod => httpMethod.ToLower() == requestHttpMethod))
                {                 // Http method is not matching
                    return(EndpointMatchResult.NoMatch);
                }

                // Check if this endpoint is ignored, allowed takes precedence
                IgnoreForBatchRequestAttribute ignoreAttribute = routeEndpoint.Metadata.GetMetadata <IgnoreForBatchRequestAttribute>();
                AllowForBatchRequestAttribute  allowAttribute  = routeEndpoint.Metadata.GetMetadata <AllowForBatchRequestAttribute>();
                if (ignoreAttribute != null && allowAttribute == null)
                {
                    return(EndpointMatchResult.Ignored);
                }

                return(EndpointMatchResult.Match);
            }
            return(EndpointMatchResult.NoMatch);
        }
Beispiel #17
0
        public void CreatesRoutes(string pattern, string resultingTemplate, string resultingTypes)
        {
            var contentTypeA = new ContentTypeDescriptor("sit", typeof(ContentTypeA));
            var contentTypeB = new ContentTypeDescriptor("dol", typeof(ContentTypeB));

            var contentTypeProvider = Mock.Of <IContentTypeProvider>();

            Mock.Get(contentTypeProvider).Setup(p => p.GetAll()).Returns(new List <ContentTypeDescriptor> {
                contentTypeA, contentTypeB
            });

            var contentTypeExpander = Mock.Of <IContentTypeExpander>();

            Mock.Get(contentTypeExpander).Setup(e => e.Expand("expandToDol")).Returns(new List <ContentTypeDescriptor> {
                contentTypeB
            });

            var endpoint   = new RouteEndpoint(async context => { }, RoutePatternFactory.Parse(pattern), 0, null, null);
            var dataSource = new CompositeEndpointDataSource(new List <EndpointDataSource> {
                new DefaultEndpointDataSource(endpoint)
            });

            var results = new ContentRouteCreator(Mock.Of <ILogger <ContentRouteCreator> >(), dataSource, contentTypeProvider, contentTypeExpander).Create();

            if (resultingTemplate == null)
            {
                Assert.Empty(results);
                return;
            }

            Assert.Single(results);

            var result = results.Single();

            Assert.Equal(resultingTemplate, result.Template);
            Assert.Equal(resultingTypes, string.Join(",", result.ContentTypes.Select(t => t.Id)));
        }
Beispiel #18
0
        public void Matcher_IgnoresUpdate_WhenDisposed()
        {
            // Arrange
            var dataSource = new DynamicEndpointDataSource();
            var lifetime   = new DataSourceDependentMatcher.Lifetime();
            var matcher    = new DataSourceDependentMatcher(dataSource, lifetime, TestMatcherBuilder.Create);

            var endpoint = new RouteEndpoint(
                TestConstants.EmptyRequestDelegate,
                RoutePatternFactory.Parse("a/b/c"),
                0,
                EndpointMetadataCollection.Empty,
                "test");

            lifetime.Dispose();

            // Act
            dataSource.AddEndpoint(endpoint);

            // Assert
            var inner = Assert.IsType <TestMatcher>(matcher.CurrentMatcher);

            Assert.Empty(inner.Endpoints);
        }
 internal TemplateBinder GetTemplateBinder(RouteEndpoint endpoint) => _cache.EnsureInitialized().GetOrAdd(endpoint, _createTemplateBinder);
 private TemplateBinder CreateTemplateBinder(RouteEndpoint endpoint)
 {
     return(_binderFactory.Create(endpoint.RoutePattern));
 }
        public IEnumerable <Endpoint> FindEndpoints(RouteValuesAddress address)
        {
            if (address.AmbientValues == null || address.ExplicitValues == null)
            {
                return(Enumerable.Empty <Endpoint>());
            }


            // Try to get the contained item first, then the container content item
            string contentItemId = address.ExplicitValues[_options.ContainedContentItemIdKey]?.ToString();

            if (string.IsNullOrEmpty(contentItemId))
            {
                contentItemId = address.ExplicitValues[_options.ContentItemIdKey]?.ToString();
            }

            if (string.IsNullOrEmpty(contentItemId))
            {
                return(Enumerable.Empty <Endpoint>());
            }

            (var found, var autorouteEntry) = _entries.TryGetEntryByContentItemIdAsync(contentItemId).GetAwaiter().GetResult();

            if (!found)
            {
                return(Enumerable.Empty <Endpoint>());
            }

            if (Match(address.ExplicitValues))
            {
                // Once we have the contained content item id value we no longer want it in the route values.
                address.ExplicitValues.Remove(_options.ContainedContentItemIdKey);

                var routeValues = new RouteValueDictionary(address.ExplicitValues);

                if (address.ExplicitValues.Count > _options.GlobalRouteValues.Count + 1)
                {
                    foreach (var entry in address.ExplicitValues)
                    {
                        if (String.Equals(entry.Key, _options.ContentItemIdKey, StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        if (!_options.GlobalRouteValues.ContainsKey(entry.Key))
                        {
                            routeValues.Remove(entry.Key);
                        }
                    }
                }

                var endpoint = new RouteEndpoint
                               (
                    c => null,
                    RoutePatternFactory.Parse(autorouteEntry.Path, routeValues, null),
                    0,
                    null,
                    null
                               );

                return(new[] { endpoint });
            }

            return(Enumerable.Empty <Endpoint>());
        }
        public TrivialMatcher(RouteEndpoint endpoint)
        {
            _endpoint = endpoint;

            _candidates = new Candidate[] { new Candidate(endpoint), };
        }
Beispiel #23
0
        public static OpenApiDocument CreateDocument(HttpContext context, string prefixName)
        {
            IDictionary <string, ODataPath> tempateToPathDict = new Dictionary <string, ODataPath>();
            ODataOpenApiPathProvider        provider          = new ODataOpenApiPathProvider();
            IEdmModel          model      = null;
            EndpointDataSource dataSource = context.RequestServices.GetRequiredService <EndpointDataSource>();

            foreach (var endpoint in dataSource.Endpoints)
            {
                IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>();
                if (metadata == null)
                {
                    continue;
                }

                if (metadata.Prefix != prefixName)
                {
                    continue;
                }
                model = metadata.Model;

                RouteEndpoint routeEndpoint = endpoint as RouteEndpoint;
                if (routeEndpoint == null)
                {
                    continue;
                }

                // get rid of the prefix
                int    length            = prefixName.Length;
                string routePathTemplate = routeEndpoint.RoutePattern.RawText.Substring(length);
                routePathTemplate = routePathTemplate.StartsWith("/") ? routePathTemplate : "/" + routePathTemplate;

                if (tempateToPathDict.TryGetValue(routePathTemplate, out ODataPath pathValue))
                {
                    var methods = GetHttpMethods(endpoint);
                    foreach (var method in methods)
                    {
                        pathValue.HttpMethods.Add(method);
                    }

                    continue;
                }

                var path = metadata.Template.Translate();
                if (path == null)
                {
                    continue;
                }

                path.PathTemplate = routePathTemplate;
                provider.Add(path);

                var method1 = GetHttpMethods(endpoint);
                foreach (var method in method1)
                {
                    path.HttpMethods.Add(method);
                }
                tempateToPathDict[routePathTemplate] = path;
            }

            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                PathProvider = provider,
                ServiceRoot  = BuildAbsolute(context, prefixName)
            };

            return(model.ConvertToOpenApi(settings));
        }
        private static ApiDescription CreateApiDescription(
            RouteEndpoint routeEndpoint,
            MethodModel methodModel,
            HttpMethodAttribute httpMethodAttribute)
        {
            var apiDescription = new ApiDescription
            {
                HttpMethod       = httpMethodAttribute.Method,
                ActionDescriptor = new ActionDescriptor
                {
                    RouteValues = new Dictionary <string, string>
                    {
                        // Swagger uses this to group endpoints together.
                        // Group methods together using the service name.
                        ["controller"] = methodModel.MethodInfo.DeclaringType?.Name ?? string.Empty
                    }
                },
                RelativePath = routeEndpoint.RoutePattern.RawText?.TrimStart('/') ?? string.Empty
            };

            apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat
            {
                MediaType = "application/json"
            });

            var responseTypes = methodModel.MethodInfo
                                .GetCustomAttributes(typeof(ProducesResponseTypeAttribute), false)
                                .OfType <ProducesResponseTypeAttribute>();

            var addDefaultResponseType = true;

            foreach (var responseType in responseTypes)
            {
                addDefaultResponseType = false;

                apiDescription.SupportedResponseTypes.Add(new ApiResponseType
                {
                    ApiResponseFormats = { new ApiResponseFormat {
                                               MediaType = "application/json"
                                           } },
                    ModelMetadata = responseType.Type == null ? null : new ExpressModelMetadata(responseType.Type),
                    StatusCode    = responseType.StatusCode,
                });
            }

            if (addDefaultResponseType)
            {
                apiDescription.SupportedResponseTypes.Add(new ApiResponseType
                {
                    ApiResponseFormats = { new ApiResponseFormat {
                                               MediaType = "application/json"
                                           } },
                    StatusCode = 200,
                });
            }

            foreach (var parameter in methodModel.Parameters)
            {
                apiDescription.ParameterDescriptions.Add(new ApiParameterDescription
                {
                    Name          = parameter.Name ?? "Input",
                    ModelMetadata = new ExpressModelMetadata(parameter.ParameterType),
                    Source        = parameter.GetBindingSource()
                });
            }

            return(apiDescription);
        }
 private static bool SupportsLinkGeneration(RouteEndpoint endpoint)
 {
     return(!(endpoint.Metadata.GetMetadata <ISuppressLinkGenerationMetadata>()?.SuppressLinkGeneration == true));
 }
        private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint)
        {
            var httpMethodMetadata = routeEndpoint.Metadata.GetMetadata <HttpMethodMetadata>();
            var verb = httpMethodMetadata?.HttpMethods.FirstOrDefault();

            var apiDescription = new Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription();

            // Default to a GET in case a Route map was registered inline - it's unlikely to be a composition handler in that case.
            apiDescription.HttpMethod       = verb ?? "GET";
            apiDescription.ActionDescriptor = new ActionDescriptor
            {
                RouteValues = new Dictionary <string, string>
                {
                    // Swagger uses this to group endpoints together.
                    // Group methods together using the service name.
                    // NOTE: Need a metadata model in service composer to begin supplying more info other than just http verbs and route patterns.
                    ["controller"] = "ViewModelComposition"// routeEndpoint.RoutePattern.GetParameter("controller").Default.ToString()
                }
            };
            apiDescription.RelativePath = routeEndpoint.RoutePattern.RawText.TrimStart('/');
            apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat {
                MediaType = "application/json"
            });

            foreach (var producesDefaultResponseTypeAttribute in routeEndpoint.Metadata.OfType <ProducesDefaultResponseTypeAttribute>())
            {
                apiDescription.SupportedResponseTypes.Add(new ApiResponseType
                {
                    Type = producesDefaultResponseTypeAttribute.Type,
                    ApiResponseFormats = { new ApiResponseFormat {
                                               MediaType = "application/json"
                                           } },
                    StatusCode        = producesDefaultResponseTypeAttribute.StatusCode,
                    IsDefaultResponse = true,
                    ModelMetadata     = _modelMetadataProvider.GetMetadataForType(producesDefaultResponseTypeAttribute.Type)
                });
            }

            foreach (var producesResponseTypeAttribute in routeEndpoint.Metadata.OfType <ProducesResponseTypeAttribute>())
            {
                apiDescription.SupportedResponseTypes.Add(new ApiResponseType
                {
                    Type = producesResponseTypeAttribute.Type,
                    ApiResponseFormats = { new ApiResponseFormat {
                                               MediaType = "application/json"
                                           } },
                    StatusCode        = producesResponseTypeAttribute.StatusCode,
                    IsDefaultResponse = false,
                    ModelMetadata     = _modelMetadataProvider.GetMetadataForType(producesResponseTypeAttribute.Type)
                });
            }

            foreach (var apiParameterDescriptionAttribute in routeEndpoint.Metadata.OfType <ApiParameterDescriptionAttribute>())
            {
                apiDescription.ParameterDescriptions.Add(new ApiParameterDescription()
                {
                    Name          = apiParameterDescriptionAttribute.Name,
                    IsRequired    = apiParameterDescriptionAttribute.IsRequired,
                    Type          = apiParameterDescriptionAttribute.Type,
                    Source        = GetBindingSource(apiParameterDescriptionAttribute.Source),
                    ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiParameterDescriptionAttribute.Type)
                });
            }

            return(apiDescription);
        }
 public override void AddEndpoint(RouteEndpoint endpoint)
 {
     _endpoints.Add(endpoint);
 }
Beispiel #28
0
            private void ProcessSegment(
                RouteEndpoint endpoint,
                List <DfaNode> parents,
                List <DfaNode> nextParents,
                RoutePatternPathSegment segment)
            {
                for (var i = 0; i < parents.Count; i++)
                {
                    var parent        = parents[i];
                    var part          = segment.Parts[0];
                    var parameterPart = part as RoutePatternParameterPart;
                    if (segment.IsSimple && part is RoutePatternLiteralPart literalPart)
                    {
                        AddLiteralNode(_includeLabel, nextParents, parent, literalPart.Content);
                    }
                    else if (segment.IsSimple && parameterPart != null && parameterPart.IsCatchAll)
                    {
                        // A catch all should traverse all literal nodes as well as parameter nodes
                        // we don't need to create the parameter node here because of ordering
                        // all catchalls will be processed after all parameters.
                        if (parent.Literals != null)
                        {
                            nextParents.AddRange(parent.Literals.Values);
                        }
                        if (parent.Parameters != null)
                        {
                            nextParents.Add(parent.Parameters);
                        }

                        // We also create a 'catchall' here. We don't do further traversals
                        // on the catchall node because only catchalls can end up here. The
                        // catchall node allows us to capture an unlimited amount of segments
                        // and also to match a zero-length segment, which a parameter node
                        // doesn't allow.
                        if (parent.CatchAll == null)
                        {
                            parent.CatchAll = new DfaNode()
                            {
                                PathDepth = parent.PathDepth + 1,
                                Label     = _includeLabel ? parent.Label + "{*...}/" : null,
                            };

                            // The catchall node just loops.
                            parent.CatchAll.Parameters = parent.CatchAll;
                            parent.CatchAll.CatchAll   = parent.CatchAll;
                        }

                        parent.CatchAll.AddMatch(endpoint);
                    }
                    else if (segment.IsSimple && parameterPart != null && TryGetRequiredValue(endpoint.RoutePattern, parameterPart, out var requiredValue))
                    {
                        // If the parameter has a matching required value, replace the parameter with the required value
                        // as a literal. This should use the parameter's transformer (if present)
                        // e.g. Template: Home/{action}, Required values: { action = "Index" }, Result: Home/Index

                        AddRequiredLiteralValue(endpoint, nextParents, parent, parameterPart, requiredValue);
                    }
                    else if (segment.IsSimple && parameterPart != null)
                    {
                        if (parent.Parameters == null)
                        {
                            parent.Parameters = new DfaNode()
                            {
                                PathDepth = parent.PathDepth + 1,
                                Label     = _includeLabel ? parent.Label + "{...}/" : null,
                            };
                        }

                        if (parent.Literals != null)
                        {
                            // If the parameter contains constraints, we can be smarter about it and evaluate them while we build the tree.
                            // If the literal doesn't match any of the constraints, we can prune the branch.
                            // For example, for a parameter in a route {lang:length(2)} and a parent literal "ABC", we can check that "ABC"
                            // doesn't meet the parameter constraint (length(2)) when building the tree, and avoid the extra nodes.
                            if (endpoint.RoutePattern.ParameterPolicies.TryGetValue(parameterPart.Name, out var parameterPolicyReferences))
                            {
                                // We filter out sibling literals that don't match one of the constraints in the segment to avoid adding nodes to the DFA
                                // that will never match a route and which will result in a much higher memory usage.
                                AddParentsWithMatchingLiteralConstraints(nextParents, parent, parameterPart, parameterPolicyReferences);
                            }
                            else
                            {
                                // This means the current parameter we are evaluating doesn't contain any constraint, so we need to
                                // traverse all literal nodes as well as the parameter node.
                                nextParents.AddRange(parent.Literals.Values);
                            }
                        }

                        nextParents.Add(parent.Parameters);
                    }
                    else
                    {
                        // Complex segment - we treat these are parameters here and do the
                        // expensive processing later. We don't want to spend time processing
                        // complex segments unless they are the best match, and treating them
                        // like parameters in the DFA allows us to do just that.
                        if (parent.Parameters == null)
                        {
                            parent.Parameters = new DfaNode()
                            {
                                PathDepth = parent.PathDepth + 1,
                                Label     = _includeLabel ? parent.Label + "{...}/" : null,
                            };
                        }

                        if (parent.Literals != null)
                        {
                            // For a complex segment like this, we can evaluate the literals and avoid adding extra nodes to
                            // the tree on cases where the literal won't ever be able to match the complex parameter.
                            // For example, if we have a complex parameter {a}-{b}.{c?} and a literal "Hello" we can guarantee
                            // that it will never be a match.

                            // We filter out sibling literals that don't match the complex parameter segment to avoid adding nodes to the DFA
                            // that will never match a route and which will result in a much higher memory usage.
                            AddParentsMatchingComplexSegment(endpoint, nextParents, segment, parent, parameterPart);
                        }
                        nextParents.Add(parent.Parameters);
                    }
                }
            }
        public ContentResult GetAllRoutes()
        {
            StringBuilder nonSb = new StringBuilder();
            StringBuilder sb    = new StringBuilder();

            foreach (var endpoint in _dataSource.Endpoints)
            {
                ControllerActionDescriptor controllerActionDescriptor = endpoint.Metadata.GetMetadata <ControllerActionDescriptor>();
                if (controllerActionDescriptor == null)
                {
                    continue;
                }

                IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>();
                if (metadata == null)
                {
                    AppendNonODataRoute(nonSb, endpoint);
                    continue;
                }

                // controller and action details
                StringBuilder action = new StringBuilder();
                if (controllerActionDescriptor.MethodInfo.ReturnType != null)
                {
                    action.Append(controllerActionDescriptor.MethodInfo.ReturnType.Name + " ");
                }
                else
                {
                    action.Append("void ");
                }
                action.Append(controllerActionDescriptor.MethodInfo.Name + "(");
                action.Append(string.Join(",", controllerActionDescriptor.MethodInfo.GetParameters().Select(p => p.ParameterType.Name)));
                action.Append(")");
                string actionName = controllerActionDescriptor.MethodInfo.Name;

                sb.Append("<tr>");
                sb.Append($"<td>{GetActionDesciption(controllerActionDescriptor)}</td>");

                // http methods
                //  string httpMethods = string.Join(",", metadata.HttpMethods);
                //  sb.Append($"<td>{httpMethods.ToUpper()}</td>");

                sb.Append($"<td>{string.Join(",", GetHttpMethods(endpoint))}</td>");

                // template name
                RouteEndpoint routeEndpoint = endpoint as RouteEndpoint;
                if (routeEndpoint != null)
                {
                    sb.Append("<td>~/").Append(routeEndpoint.RoutePattern.RawText).Append("</td></tr>");
                }
                else
                {
                    sb.Append("<td>---NON RouteEndpoint---</td></tr>");
                }
            }

            string output = ODataRouteMappingHtmlTemplate.Replace("{CONTENT}", sb.ToString());

            output = output.Replace("{NONENDPOINTCONTENT}", nonSb.ToString());

            return(base.Content(output, "text/html"));
        }
Beispiel #30
0
    private static ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint, HttpRule httpRule, MethodDescriptor methodDescriptor, string pattern, string verb)
    {
        var apiDescription = new ApiDescription();

        apiDescription.HttpMethod       = verb;
        apiDescription.ActionDescriptor = new ActionDescriptor
        {
            RouteValues = new Dictionary <string, string?>
            {
                // Swagger uses this to group endpoints together.
                // Group methods together using the service name.
                ["controller"] = methodDescriptor.Service.FullName
            },
            EndpointMetadata = routeEndpoint.Metadata.ToList()
        };
        apiDescription.RelativePath = pattern.TrimStart('/');
        apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat {
            MediaType = "application/json"
        });
        apiDescription.SupportedResponseTypes.Add(new ApiResponseType
        {
            ApiResponseFormats = { new ApiResponseFormat {
                                       MediaType = "application/json"
                                   } },
            ModelMetadata = new GrpcModelMetadata(ModelMetadataIdentity.ForType(methodDescriptor.OutputType.ClrType)),
            StatusCode    = 200
        });
        var explorerSettings = routeEndpoint.Metadata.GetMetadata <ApiExplorerSettingsAttribute>();

        if (explorerSettings != null)
        {
            apiDescription.GroupName = explorerSettings.GroupName;
        }

        var methodMetadata  = routeEndpoint.Metadata.GetMetadata <GrpcMethodMetadata>() !;
        var routeParameters = ServiceDescriptorHelpers.ResolveRouteParameterDescriptors(routeEndpoint.RoutePattern, methodDescriptor.InputType);

        foreach (var routeParameter in routeParameters)
        {
            var field         = routeParameter.Value.Last();
            var parameterName = ServiceDescriptorHelpers.FormatUnderscoreName(field.Name, pascalCase: true, preservePeriod: false);
            var propertyInfo  = field.ContainingType.ClrType.GetProperty(parameterName);

            // If from a property, create model as property to get its XML comments.
            var identity = propertyInfo != null
                ? ModelMetadataIdentity.ForProperty(propertyInfo, MessageDescriptorHelpers.ResolveFieldType(field), field.ContainingType.ClrType)
                : ModelMetadataIdentity.ForType(MessageDescriptorHelpers.ResolveFieldType(field));

            apiDescription.ParameterDescriptions.Add(new ApiParameterDescription
            {
                Name          = routeParameter.Key,
                ModelMetadata = new GrpcModelMetadata(identity),
                Source        = BindingSource.Path,
                DefaultValue  = string.Empty
            });
        }

        var bodyDescriptor = ServiceDescriptorHelpers.ResolveBodyDescriptor(httpRule.Body, methodMetadata.ServiceType, methodDescriptor);

        if (bodyDescriptor != null)
        {
            // If from a property, create model as property to get its XML comments.
            var identity = bodyDescriptor.PropertyInfo != null
                ? ModelMetadataIdentity.ForProperty(bodyDescriptor.PropertyInfo, bodyDescriptor.Descriptor.ClrType, bodyDescriptor.PropertyInfo.DeclaringType !)
                : ModelMetadataIdentity.ForType(bodyDescriptor.Descriptor.ClrType);

            // Or if from a parameter, create model as parameter to get its XML comments.
            var parameterDescriptor = bodyDescriptor.ParameterInfo != null
                ? new ControllerParameterDescriptor {
                ParameterInfo = bodyDescriptor.ParameterInfo
            }
                : null;

            apiDescription.ParameterDescriptions.Add(new ApiParameterDescription
            {
                Name                = "Input",
                ModelMetadata       = new GrpcModelMetadata(identity),
                Source              = BindingSource.Body,
                ParameterDescriptor = parameterDescriptor !
            });