protected RouteEndpoint CreateEndpoint(
            string template,
            object defaults       = null,
            object constraints    = null,
            object requiredValues = null,
            int order             = 0,
            string displayName    = null,
            string routeName      = null,
            params object[] metadata)
        {
            var endpointMetadata = new List <object>(metadata ?? Array.Empty <object>());

            if (routeName != null)
            {
                endpointMetadata.Add(new RouteNameMetadata(routeName));
            }

            return(new RouteEndpoint(
                       (context) => Task.CompletedTask,
                       RoutePatternFactory.Parse(template, defaults, constraints, requiredValues),
                       order,
                       new EndpointMetadataCollection(endpointMetadata),
                       displayName));
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithArgumentAndMultipleServices()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithMultipleArguments));

            var services = new ServiceCollection();

            services.AddTransient <ITestService, TestService>();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20,-1)");

            // Assert
            var constraint = Assert.IsType <CustomParameterPolicyWithMultipleArguments>(parameterPolicy);

            Assert.Equal(20, constraint.First);
            Assert.Equal(-1, constraint.Second);
            Assert.NotNull(constraint.TestService1);
            Assert.NotNull(constraint.TestService2);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Adds a GraphQL endpoint to the endpoint configurations.
        /// </summary>
        /// <param name="endpointRouteBuilder">
        /// The <see cref="IEndpointConventionBuilder"/>.
        /// </param>
        /// <param name="path">
        /// The path to which the GraphQL endpoint shall be mapped.
        /// </param>
        /// <param name="schemaName">
        /// The name of the schema that shall be used by this endpoint.
        /// </param>
        /// <returns>
        /// Returns the <see cref="IEndpointConventionBuilder"/> so that
        /// configuration can be chained.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="endpointRouteBuilder" /> is <c>null</c>.
        /// </exception>
        public static GraphQLEndpointConventionBuilder MapGraphQL(
            this IEndpointRouteBuilder endpointRouteBuilder,
            PathString path,
            NameString schemaName = default)
        {
            if (endpointRouteBuilder is null)
            {
                throw new ArgumentNullException(nameof(endpointRouteBuilder));
            }

            path = path.ToString().TrimEnd('/');

            RoutePattern        pattern             = RoutePatternFactory.Parse(path + "/{**slug}");
            IApplicationBuilder requestPipeline     = endpointRouteBuilder.CreateApplicationBuilder();
            NameString          schemaNameOrDefault = schemaName.HasValue ? schemaName : Schema.DefaultName;
            IFileProvider       fileProvider        = CreateFileProvider();

            requestPipeline
            .UseMiddleware <WebSocketSubscriptionMiddleware>(schemaNameOrDefault)
            .UseMiddleware <HttpPostMiddleware>(schemaNameOrDefault)
            .UseMiddleware <HttpGetSchemaMiddleware>(schemaNameOrDefault)
            .UseMiddleware <ToolDefaultFileMiddleware>(fileProvider, path)
            .UseMiddleware <ToolOptionsFileMiddleware>(schemaNameOrDefault, path)
            .UseMiddleware <ToolStaticFileMiddleware>(fileProvider, path)
            .UseMiddleware <HttpGetMiddleware>(schemaNameOrDefault)
            .Use(next => context =>
            {
                context.Response.StatusCode = 404;
                return(Task.CompletedTask);
            });

            return(new GraphQLEndpointConventionBuilder(
                       endpointRouteBuilder
                       .Map(pattern, requestPipeline.Build())
                       .WithDisplayName("Hot Chocolate GraphQL Pipeline")));
        }
        public void Matcher_Reinitializes_WhenDataSourceChanges()
        {
            // Arrange
            var dataSource = new DynamicEndpointDataSource();
            var matcher    = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create);

            var endpoint = new MatcherEndpoint(
                MatcherEndpoint.EmptyInvoker,
                RoutePatternFactory.Parse("a/b/c"),
                new RouteValueDictionary(),
                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));
        }
Ejemplo n.º 5
0
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRouting();

            var endpointDataSource = new DefaultEndpointDataSource(new[]
            {
                new MatcherEndpoint(
                    invoker: (next) => (httpContext) =>
                {
                    var response           = httpContext.Response;
                    var payloadLength      = _helloWorldPayload.Length;
                    response.StatusCode    = 200;
                    response.ContentType   = "text/plain";
                    response.ContentLength = payloadLength;
                    return(response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength));
                },
                    routePattern: RoutePatternFactory.Parse("/plaintext"),
                    order: 0,
                    metadata: EndpointMetadataCollection.Empty,
                    displayName: "Plaintext"),
            });

            services.TryAddEnumerable(ServiceDescriptor.Singleton <EndpointDataSource>(endpointDataSource));
        }
Ejemplo n.º 6
0
        internal static RouteEndpoint CreateEndpoint(
            string template,
            object defaults          = null,
            object constraints       = null,
            int order                = 0,
            string[] httpMethods     = null,
            bool acceptCorsPreflight = false)
        {
            var metadata = new List <object>();

            if (httpMethods != null)
            {
                metadata.Add(new HttpMethodMetadata(httpMethods ?? Array.Empty <string>(), acceptCorsPreflight));
            }

            var displayName = "endpoint: " + template + " " + string.Join(", ", httpMethods ?? new[] { "(any)" });

            return(new RouteEndpoint(
                       TestConstants.EmptyRequestDelegate,
                       RoutePatternFactory.Parse(template, defaults, constraints),
                       order,
                       new EndpointMetadataCollection(metadata),
                       displayName));
        }
    public void SubstituteRequiredValues_AllowRequiredValueAnyForParameter()
    {
        // Arrange
        var template = "{controller=Home}/{action=Index}/{id?}";
        var defaults = new { };
        var policies = new { };

        var original = RoutePatternFactory.Parse(template, defaults, policies);

        var requiredValues = new { controller = RoutePattern.RequiredValueAny, };

        // Act
        var actual = Transformer.SubstituteRequiredValues(original, requiredValues);

        // Assert
        Assert.Collection(
            actual.Defaults.OrderBy(kvp => kvp.Key),
            kvp => Assert.Equal(new KeyValuePair <string, object>("action", "Index"), kvp),
            kvp => Assert.Equal(new KeyValuePair <string, object>("controller", "Home"), kvp)); // default is preserved

        Assert.Collection(
            actual.RequiredValues.OrderBy(kvp => kvp.Key),
            kvp => Assert.Equal(new KeyValuePair <string, object>("controller", RoutePattern.RequiredValueAny), kvp));
    }
Ejemplo n.º 8
0
        public static MatcherEndpoint CreateMatcherEndpoint(
            string template,
            object defaults       = null,
            object constraints    = null,
            object requiredValues = null,
            int order             = 0,
            string displayName    = null,
            params object[] metadata)
        {
            var metadataCollection = EndpointMetadataCollection.Empty;

            if (metadata != null)
            {
                metadataCollection = new EndpointMetadataCollection(metadata);
            }

            return(new MatcherEndpoint(
                       MatcherEndpoint.EmptyInvoker,
                       RoutePatternFactory.Parse(template, defaults, constraints),
                       new RouteValueDictionary(requiredValues),
                       order,
                       metadataCollection,
                       displayName));
        }
Ejemplo n.º 9
0
        public void Matcher_Reinitializes_WhenDataSourceChanges()
        {
            // 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");

            // Act
            dataSource.AddEndpoint(endpoint);

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

            Assert.Collection(
                inner.Endpoints,
                e => Assert.Same(endpoint, e));
        }
Ejemplo n.º 10
0
        public static void MapMediatR(this IEndpointRouteBuilder endpointsBuilder)
        {
            var mediator = endpointsBuilder.ServiceProvider.GetService <IMediator>();

            if (mediator == null)
            {
                throw new InvalidOperationException($"IMediator has not added to IServiceCollection. You can add it with services.AddMediatR(...);");
            }

            var mediatorEndpointCollections = endpointsBuilder.ServiceProvider.GetService <MediatorEndpointCollections>();

            foreach (var endpoint in mediatorEndpointCollections.Endpoints)
            {
                var routePattern = RoutePatternFactory.Parse(endpoint.Uri);

                var builder = endpointsBuilder.Map(routePattern, MediatorRequestDelegate);
                builder.WithDisplayName(endpoint.RequestType.Name);

                for (var i = 0; i < endpoint.Metadata.Count; i++)
                {
                    builder.WithMetadata(endpoint.Metadata[i]);
                }
            }
        }
Ejemplo n.º 11
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);
        }
Ejemplo n.º 12
0
        public void AddEndpoints(
            List <Endpoint> endpoints,
            HashSet <string> routeNames,
            ActionDescriptor action,
            IReadOnlyList <ConventionalRouteEntry> routes,
            IReadOnlyList <Action <EndpointBuilder> > conventions)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

            if (routeNames == null)
            {
                throw new ArgumentNullException(nameof(routeNames));
            }

            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            if (routes == null)
            {
                throw new ArgumentNullException(nameof(routes));
            }

            if (conventions == null)
            {
                throw new ArgumentNullException(nameof(conventions));
            }

            if (action.AttributeRouteInfo == null)
            {
                // Check each of the conventional patterns to see if the action would be reachable.
                // If the action and pattern are compatible then create an endpoint with action
                // route values on the pattern.
                foreach (var route in routes)
                {
                    // A route is applicable if:
                    // 1. It has a parameter (or default value) for 'required' non-null route value
                    // 2. It does not have a parameter (or default value) for 'required' null route value
                    var updatedRoutePattern = _routePatternTransformer.SubstituteRequiredValues(route.Pattern, action.RouteValues);
                    if (updatedRoutePattern == null)
                    {
                        continue;
                    }

                    // We suppress link generation for each conventionally routed endpoint. We generate a single endpoint per-route
                    // to handle link generation.
                    var builder = CreateEndpoint(
                        routeNames,
                        action,
                        updatedRoutePattern,
                        route.RouteName,
                        route.Order,
                        route.DataTokens,
                        suppressLinkGeneration: true,
                        suppressPathMatching: false,
                        conventions,
                        route.Conventions);
                    endpoints.Add(builder);
                }
            }
            else
            {
                var attributeRoutePattern = RoutePatternFactory.Parse(action.AttributeRouteInfo.Template);

                // Modify the route and required values to ensure required values can be successfully subsituted.
                // Subsitituting required values into an attribute route pattern should always succeed.
                var(resolvedRoutePattern, resolvedRouteValues) = ResolveDefaultsAndRequiredValues(action, attributeRoutePattern);

                var updatedRoutePattern = _routePatternTransformer.SubstituteRequiredValues(resolvedRoutePattern, resolvedRouteValues);
                if (updatedRoutePattern == null)
                {
                    throw new InvalidOperationException("Failed to update route pattern with required values.");
                }

                var endpoint = CreateEndpoint(
                    routeNames,
                    action,
                    updatedRoutePattern,
                    action.AttributeRouteInfo.Name,
                    action.AttributeRouteInfo.Order,
                    dataTokens: null,
                    action.AttributeRouteInfo.SuppressLinkGeneration,
                    action.AttributeRouteInfo.SuppressPathMatching,
                    conventions,
                    perRouteConventions: Array.Empty <Action <EndpointBuilder> >());
                endpoints.Add(endpoint);
            }
        }
Ejemplo n.º 13
0
        public LinkGeneratorIntegrationTest()
        {
            var endpoints = new List <Endpoint>()
            {
                // Attribute routed endpoint 1
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "api/Pets/{id}",
                        defaults: new { controller = "Pets", action = "GetById", },
                        parameterPolicies: null,
                        requiredValues: new { controller = "Pets", action = "GetById", area = (string)null, page = (string)null, }),
                    order: 0),

                // Attribute routed endpoint 2
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "api/Pets",
                        defaults: new { controller = "Pets", action = "GetAll", },
                        parameterPolicies: null,
                        requiredValues: new { controller = "Pets", action = "GetAll", area = (string)null, page = (string)null, }),
                    order: 0),

                // Attribute routed endpoint 2
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "api/Pets/{id}",
                        defaults: new { controller = "Pets", action = "Update", },
                        parameterPolicies: null,
                        requiredValues: new { controller = "Pets", action = "Update", area = (string)null, page = (string)null, }),
                    order: 0),

                // Attribute routed endpoint 4
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "api/Inventory/{searchTerm}/{page}",
                        defaults: new { controller = "Inventory", action = "Search", },
                        parameterPolicies: null,
                        requiredValues: new { controller = "Inventory", action = "Search", area = (string)null, page = (string)null, }),
                    order: 0),

                // Conventional routed endpoint 1
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "{controller=Home}/{action=Index}/{id?}",
                        defaults: null,
                        parameterPolicies: null,
                        requiredValues: new { controller = "Home", action = "Index", area = (string)null, page = (string)null, }),
                    order: 2000,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),

                // Conventional routed endpoint 2
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "{controller=Home}/{action=Index}/{id?}",
                        defaults: null,
                        parameterPolicies: null,
                        requiredValues: new { controller = "Home", action = "About", area = (string)null, page = (string)null, }),
                    order: 2000,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),

                // Conventional routed endpoint 3
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "{controller=Home}/{action=Index}/{id?}",
                        defaults: null,
                        parameterPolicies: null,
                        requiredValues: new { controller = "Store", action = "Browse", area = (string)null, page = (string)null, }),
                    order: 2000,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),

                // Conventional routed link generation route 1
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "{controller=Home}/{action=Index}/{id?}",
                        defaults: null,
                        parameterPolicies: null,
                        requiredValues: new { controller = RoutePattern.RequiredValueAny, action = RoutePattern.RequiredValueAny, area = (string)null, page = (string)null, }),
                    order: 2000,
                    metadata: new object[] { new SuppressMatchingMetadata(), }),

                // Conventional routed endpoint 4 (with area)
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Admin/{controller=Home}/{action=Index}/{id?}",
                        defaults: new { area = "Admin", },
                        parameterPolicies: new { controller = "Admin", },
                        requiredValues: new { area = "Admin", controller = "Users", action = "Add", page = (string)null, }),
                    order: 1000,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),

                // Conventional routed endpoint 5 (with area)
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Admin/{controller=Home}/{action=Index}/{id?}",
                        defaults: new { area = "Admin", },
                        parameterPolicies: new { controller = "Admin", },
                        requiredValues: new { area = "Admin", controller = "Users", action = "Remove", page = (string)null, }),
                    order: 1000,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),

                // Conventional routed link generation route 2
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Admin/{controller=Home}/{action=Index}/{id?}",
                        defaults: new { area = "Admin", },
                        parameterPolicies: new { area = "Admin", },
                        requiredValues: new { controller = RoutePattern.RequiredValueAny, action = RoutePattern.RequiredValueAny, area = "Admin", page = (string)null, }),
                    order: 1000,
                    metadata: new object[] { new SuppressMatchingMetadata(), }),

                // Conventional routed link generation route 3 - this doesn't match any actions.
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "api/{controller}/{id?}",
                        defaults: new { },
                        parameterPolicies: new { },
                        requiredValues: new { controller = RoutePattern.RequiredValueAny, action = (string)null, area = (string)null, page = (string)null, }),
                    order: 3000,
                    metadata: new object[] { new SuppressMatchingMetadata(), new RouteNameMetadata("custom"), }),

                // Conventional routed link generation route 3 - this doesn't match any actions.
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "api/Foo/{custom2}",
                        defaults: new { },
                        parameterPolicies: new { },
                        requiredValues: new { controller = (string)null, action = (string)null, area = (string)null, page = (string)null, }),
                    order: 3000,
                    metadata: new object[] { new SuppressMatchingMetadata(), new RouteNameMetadata("custom2"), }),

                // Razor Page 1 primary endpoint
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Pages",
                        defaults: new { page = "/Pages/Index", },
                        parameterPolicies: null,
                        requiredValues: new { controller = (string)null, action = (string)null, area = (string)null, page = "/Pages/Index", }),
                    order: 0),

                // Razor Page 1 secondary endpoint
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Pages/Index",
                        defaults: new { page = "/Pages/Index", },
                        parameterPolicies: null,
                        requiredValues: new { controller = (string)null, action = (string)null, area = (string)null, page = "/Pages/Index", }),
                    order: 0,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),

                // Razor Page 2 primary endpoint
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Pages/Help/{id?}",
                        defaults: new { page = "/Pages/Help", },
                        parameterPolicies: null,
                        requiredValues: new { controller = (string)null, action = (string)null, area = (string)null, page = "/Pages/Help", }),
                    order: 0),

                // Razor Page 3 primary endpoint
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Pages/About/{id?}",
                        defaults: new { page = "/Pages/About", },
                        parameterPolicies: null,
                        requiredValues: new { controller = (string)null, action = (string)null, area = (string)null, page = "/Pages/About", }),
                    order: 0),

                // Razor Page 4 with area primary endpoint
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Admin/Pages",
                        defaults: new { page = "/Pages/Index", area = "Admin", },
                        parameterPolicies: null,
                        requiredValues: new { controller = (string)null, action = (string)null, area = "Admin", page = "/Pages/Index", }),
                    order: 0),

                // Razor Page 4 with area secondary endpoint
                EndpointFactory.CreateRouteEndpoint(
                    RoutePatternFactory.Parse(
                        "Admin/Pages/Index",
                        defaults: new { page = "/Pages/Index", area = "Admin", },
                        parameterPolicies: null,
                        requiredValues: new { controller = (string)null, action = (string)null, area = "Admin", page = "/Pages/Index", }),
                    order: 0,
                    metadata: new object[] { new SuppressLinkGenerationMetadata(), }),
            };

            Endpoints     = endpoints;
            LinkGenerator = CreateLinkGenerator(endpoints.ToArray());
        }
Ejemplo n.º 14
0
        private void UpdatePathSegments(
            int i,
            ActionDescriptor action,
            IDictionary <string, string> resolvedRequiredValues,
            RoutePattern routePattern,
            List <RoutePatternPathSegment> newPathSegments,
            ref IDictionary <string, IList <IParameterPolicy> > allParameterPolicies)
        {
            List <RoutePatternPart> segmentParts = null; // Initialize only as needed
            var segment = newPathSegments[i];

            for (var j = 0; j < segment.Parts.Count; j++)
            {
                var part = segment.Parts[j];

                if (part is RoutePatternParameterPart parameterPart)
                {
                    if (resolvedRequiredValues.TryGetValue(parameterPart.Name, out var parameterRouteValue))
                    {
                        if (segmentParts == null)
                        {
                            segmentParts = segment.Parts.ToList();
                        }
                        if (allParameterPolicies == null)
                        {
                            allParameterPolicies = MvcEndpointInfo.BuildParameterPolicies(routePattern.Parameters, _parameterPolicyFactory);
                        }

                        // Route value could be null if it is a "known" route value.
                        // Do not use the null value to de-normalize the route pattern,
                        // instead leave the parameter unchanged.
                        // e.g.
                        //     RouteValues will contain a null "page" value if there are Razor pages
                        //     Skip replacing the {page} parameter
                        if (parameterRouteValue != null)
                        {
                            if (allParameterPolicies.TryGetValue(parameterPart.Name, out var parameterPolicies))
                            {
                                // Check if the parameter has a transformer policy
                                // Use the first transformer policy
                                for (var k = 0; k < parameterPolicies.Count; k++)
                                {
                                    if (parameterPolicies[k] is IOutboundParameterTransformer parameterTransformer)
                                    {
                                        parameterRouteValue = parameterTransformer.TransformOutbound(parameterRouteValue);
                                        break;
                                    }
                                }
                            }

                            segmentParts[j] = RoutePatternFactory.LiteralPart(parameterRouteValue);
                        }
                    }
                }
            }

            // A parameter part was replaced so replace segment with updated parts
            if (segmentParts != null)
            {
                newPathSegments[i] = RoutePatternFactory.Segment(segmentParts);
            }
        }
    public void RequireAuthorization_IAuthorizeData()
    {
        // Arrange
        var builder  = new TestEndpointConventionBuilder();
        var metadata = new AuthorizeAttribute();

        // Act
        builder.RequireAuthorization(metadata);

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        convention(endpointModel);

        Assert.Equal(metadata, Assert.Single(endpointModel.Metadata));
    }
 private static RouteEndpointBuilder CreateEndpointBuilder(ProxyRoute proxyRoute, Cluster cluster)
 {
     var endpointBuilder = new RouteEndpointBuilder(context => Task.CompletedTask, RoutePatternFactory.Parse(""), 0);
     var routeConfig     = new RouteConfig(
         proxyRoute,
         new ClusterInfo("cluster-1")
     {
         Config = new ClusterConfig(cluster, default)
     },
Ejemplo n.º 17
0
        public RoutePattern ToRoutePattern()
        {
            var segments = Segments.Select(s => s.ToRoutePatternPathSegment());

            return(RoutePatternFactory.Pattern(TemplateText, segments));
        }
Ejemplo n.º 18
0
 public static MethodModel Route(this MethodModel model, string template)
 {
     template           = template ?? throw new ArgumentNullException(nameof(template));
     model.RoutePattern = template == null ? null : RoutePatternFactory.Parse(template);
     return(model);
 }
    public void AllowAnonymous_Default()
    {
        // Arrange
        var builder = new TestEndpointConventionBuilder();

        // Act
        builder.AllowAnonymous();

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        convention(endpointModel);

        Assert.IsAssignableFrom <IAllowAnonymous>(Assert.Single(endpointModel.Metadata));
    }
    public void RequireAuthorization_PolicyWithAuthorize()
    {
        // Arrange
        var builder   = new TestEndpointConventionBuilder();
        var policy    = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
        var authorize = new AuthorizeAttribute();

        // Act
        builder.RequireAuthorization(policy);

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        endpointModel.Metadata.Add(authorize);
        convention(endpointModel);

        // Confirm that we don't add another authorize if one already exists
        Assert.Equal(2, endpointModel.Metadata.Count);
        Assert.Equal(authorize, endpointModel.Metadata[0]);
        Assert.Equal(policy, endpointModel.Metadata[1]);
    }
    public void RequireAuthorization_PolicyCallbackWithAuthorize()
    {
        // Arrange
        var builder     = new TestEndpointConventionBuilder();
        var authorize   = new AuthorizeAttribute();
        var requirement = new TestRequirement();

        // Act
        builder.RequireAuthorization(policyBuilder => policyBuilder.Requirements.Add(requirement));

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        endpointModel.Metadata.Add(authorize);
        convention(endpointModel);

        // Confirm that we don't add another authorize if one already exists
        Assert.Equal(2, endpointModel.Metadata.Count);
        Assert.Equal(authorize, endpointModel.Metadata[0]);
        var policy = Assert.IsAssignableFrom <AuthorizationPolicy>(endpointModel.Metadata[1]);

        Assert.Equal(1, policy.Requirements.Count);
        Assert.Equal(requirement, policy.Requirements[0]);
    }
    public void RequireAuthorization_PolicyCallback()
    {
        // Arrange
        var builder     = new TestEndpointConventionBuilder();
        var requirement = new TestRequirement();

        // Act
        builder.RequireAuthorization(policyBuilder => policyBuilder.Requirements.Add(requirement));

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        convention(endpointModel);

        Assert.Equal(2, endpointModel.Metadata.Count);
        var authMetadata = Assert.IsAssignableFrom <IAuthorizeData>(endpointModel.Metadata[0]);

        Assert.Null(authMetadata.Policy);

        var policy = Assert.IsAssignableFrom <AuthorizationPolicy>(endpointModel.Metadata[1]);

        Assert.Equal(1, policy.Requirements.Count);
        Assert.Equal(requirement, policy.Requirements[0]);
    }
    public void RequireAuthorization_Policy()
    {
        // Arrange
        var builder = new TestEndpointConventionBuilder();
        var policy  = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();

        // Act
        builder.RequireAuthorization(policy);

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        convention(endpointModel);

        Assert.Equal(2, endpointModel.Metadata.Count);
        var authMetadata = Assert.IsAssignableFrom <IAuthorizeData>(endpointModel.Metadata[0]);

        Assert.Null(authMetadata.Policy);

        Assert.Equal(policy, endpointModel.Metadata[1]);
    }
Ejemplo n.º 24
0
        public RoutePatternPathSegment ToRoutePatternPathSegment()
        {
            var parts = Parts.Select(p => p.ToRoutePatternPart());

            return(RoutePatternFactory.Segment(parts));
        }
Ejemplo n.º 25
0
        public Endpoint CreateEndpoint(RouteModel route, IReadOnlyList <Action <EndpointBuilder> > conventions)
        {
            var config = route.Config;
            var match  = config.Match;

            // Catch-all pattern when no path was specified
            var pathPattern = string.IsNullOrEmpty(match.Path) ? "/{**catchall}" : match.Path;

            var endpointBuilder = new RouteEndpointBuilder(
                requestDelegate: _pipeline ?? throw new InvalidOperationException("The pipeline hasn't been provided yet."),
                routePattern: RoutePatternFactory.Parse(pathPattern),
                order: config.Order.GetValueOrDefault())
            {
                DisplayName = config.RouteId
            };

            endpointBuilder.Metadata.Add(route);

            if (match.Hosts != null && match.Hosts.Count != 0)
            {
                endpointBuilder.Metadata.Add(new HostAttribute(match.Hosts.ToArray()));
            }

            if (match.Headers != null && match.Headers.Count > 0)
            {
                var matchers = new List <HeaderMatcher>(match.Headers.Count);
                foreach (var header in match.Headers)
                {
                    matchers.Add(new HeaderMatcher(header.Name, header.Values, header.Mode, header.IsCaseSensitive));
                }

                endpointBuilder.Metadata.Add(new HeaderMetadata(matchers));
            }

            if (match.QueryParameters != null && match.QueryParameters.Count > 0)
            {
                var matchers = new List <QueryParameterMatcher>(match.QueryParameters.Count);
                foreach (var queryparam in match.QueryParameters)
                {
                    matchers.Add(new QueryParameterMatcher(queryparam.Name, queryparam.Values, queryparam.Mode, queryparam.IsCaseSensitive));
                }

                endpointBuilder.Metadata.Add(new QueryParameterMetadata(matchers));
            }

            bool acceptCorsPreflight;

            if (string.Equals(CorsConstants.Default, config.CorsPolicy, StringComparison.OrdinalIgnoreCase))
            {
                endpointBuilder.Metadata.Add(_defaultCors);
                acceptCorsPreflight = true;
            }
            else if (string.Equals(CorsConstants.Disable, config.CorsPolicy, StringComparison.OrdinalIgnoreCase))
            {
                endpointBuilder.Metadata.Add(_disableCors);
                acceptCorsPreflight = true;
            }
            else if (!string.IsNullOrEmpty(config.CorsPolicy))
            {
                endpointBuilder.Metadata.Add(new EnableCorsAttribute(config.CorsPolicy));
                acceptCorsPreflight = true;
            }
            else
            {
                acceptCorsPreflight = false;
            }

            if (match.Methods != null && match.Methods.Count > 0)
            {
                endpointBuilder.Metadata.Add(new HttpMethodMetadata(match.Methods, acceptCorsPreflight));
            }

            if (string.Equals(AuthorizationConstants.Default, config.AuthorizationPolicy, StringComparison.OrdinalIgnoreCase))
            {
                endpointBuilder.Metadata.Add(_defaultAuthorization);
            }
            else if (string.Equals(AuthorizationConstants.Anonymous, config.AuthorizationPolicy, StringComparison.OrdinalIgnoreCase))
            {
                endpointBuilder.Metadata.Add(_allowAnonymous);
            }
            else if (!string.IsNullOrEmpty(config.AuthorizationPolicy))
            {
                endpointBuilder.Metadata.Add(new AuthorizeAttribute(config.AuthorizationPolicy));
            }

            for (var i = 0; i < conventions.Count; i++)
            {
                conventions[i](endpointBuilder);
            }

            return(endpointBuilder.Build());
        }
        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>());
        }
Ejemplo n.º 27
0
    public void AddEndpoints(
        List <Endpoint> endpoints,
        HashSet <string> routeNames,
        ActionDescriptor action,
        IReadOnlyList <ConventionalRouteEntry> routes,
        IReadOnlyList <Action <EndpointBuilder> > conventions,
        bool createInertEndpoints)
    {
        if (endpoints == null)
        {
            throw new ArgumentNullException(nameof(endpoints));
        }

        if (routeNames == null)
        {
            throw new ArgumentNullException(nameof(routeNames));
        }

        if (action == null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        if (routes == null)
        {
            throw new ArgumentNullException(nameof(routes));
        }

        if (conventions == null)
        {
            throw new ArgumentNullException(nameof(conventions));
        }

        if (createInertEndpoints)
        {
            var builder = new InertEndpointBuilder()
            {
                DisplayName     = action.DisplayName,
                RequestDelegate = _requestDelegate,
            };
            AddActionDataToBuilder(
                builder,
                routeNames,
                action,
                routeName: null,
                dataTokens: null,
                suppressLinkGeneration: false,
                suppressPathMatching: false,
                conventions,
                Array.Empty <Action <EndpointBuilder> >());
            endpoints.Add(builder.Build());
        }

        if (action.AttributeRouteInfo?.Template == null)
        {
            // Check each of the conventional patterns to see if the action would be reachable.
            // If the action and pattern are compatible then create an endpoint with action
            // route values on the pattern.
            foreach (var route in routes)
            {
                // A route is applicable if:
                // 1. It has a parameter (or default value) for 'required' non-null route value
                // 2. It does not have a parameter (or default value) for 'required' null route value
                var updatedRoutePattern = _routePatternTransformer.SubstituteRequiredValues(route.Pattern, action.RouteValues);
                if (updatedRoutePattern == null)
                {
                    continue;
                }

                var requestDelegate = CreateRequestDelegate(action, route.DataTokens) ?? _requestDelegate;

                // We suppress link generation for each conventionally routed endpoint. We generate a single endpoint per-route
                // to handle link generation.
                var builder = new RouteEndpointBuilder(requestDelegate, updatedRoutePattern, route.Order)
                {
                    DisplayName = action.DisplayName,
                };
                AddActionDataToBuilder(
                    builder,
                    routeNames,
                    action,
                    route.RouteName,
                    route.DataTokens,
                    suppressLinkGeneration: true,
                    suppressPathMatching: false,
                    conventions,
                    route.Conventions);
                endpoints.Add(builder.Build());
            }
        }
        else
        {
            var requestDelegate       = CreateRequestDelegate(action) ?? _requestDelegate;
            var attributeRoutePattern = RoutePatternFactory.Parse(action.AttributeRouteInfo.Template);

            // Modify the route and required values to ensure required values can be successfully subsituted.
            // Subsitituting required values into an attribute route pattern should always succeed.
            var(resolvedRoutePattern, resolvedRouteValues) = ResolveDefaultsAndRequiredValues(action, attributeRoutePattern);

            var updatedRoutePattern = _routePatternTransformer.SubstituteRequiredValues(resolvedRoutePattern, resolvedRouteValues);
            if (updatedRoutePattern == null)
            {
                // This kind of thing can happen when a route pattern uses a *reserved* route value such as `action`.
                // See: https://github.com/dotnet/aspnetcore/issues/14789
                var formattedRouteKeys = string.Join(", ", resolvedRouteValues.Keys.Select(k => $"'{k}'"));
                throw new InvalidOperationException(
                          $"Failed to update the route pattern '{resolvedRoutePattern.RawText}' with required route values. " +
                          $"This can occur when the route pattern contains parameters with reserved names such as: {formattedRouteKeys} " +
                          $"and also uses route constraints such as '{{action:int}}'. " +
                          "To fix this error, choose a different parameter name.");
            }

            var builder = new RouteEndpointBuilder(requestDelegate, updatedRoutePattern, action.AttributeRouteInfo.Order)
            {
                DisplayName = action.DisplayName,
            };
            AddActionDataToBuilder(
                builder,
                routeNames,
                action,
                action.AttributeRouteInfo.Name,
                dataTokens: null,
                action.AttributeRouteInfo.SuppressLinkGeneration,
                action.AttributeRouteInfo.SuppressPathMatching,
                conventions,
                perRouteConventions: Array.Empty <Action <EndpointBuilder> >());
            endpoints.Add(builder.Build());
        }
    }
Ejemplo n.º 28
0
        private void UpdateEndpoints()
        {
            lock (_lock)
            {
                var           endpoints            = new List <Endpoint>();
                StringBuilder patternStringBuilder = null;

                foreach (var action in _actions.ActionDescriptors.Items)
                {
                    if (action.AttributeRouteInfo == null)
                    {
                        // In traditional conventional routing setup, the routes defined by a user have a static order
                        // defined by how they are added into the list. We would like to maintain the same order when building
                        // up the endpoints too.
                        //
                        // Start with an order of '1' for conventional routes as attribute routes have a default order of '0'.
                        // This is for scenarios dealing with migrating existing Router based code to Endpoint Routing world.
                        var conventionalRouteOrder = 1;

                        // Check each of the conventional patterns to see if the action would be reachable
                        // If the action and pattern are compatible then create an endpoint with the
                        // area/controller/action parameter parts replaced with literals
                        //
                        // e.g. {controller}/{action} with HomeController.Index and HomeController.Login
                        // would result in endpoints:
                        // - Home/Index
                        // - Home/Login
                        foreach (var endpointInfo in ConventionalEndpointInfos)
                        {
                            if (endpointInfo.ControllerType != null &&
                                endpointInfo.ControllerType != typeof(ControllerBase))
                            {
                                if (!ValidateControllerConstraint(action, endpointInfo))
                                {
                                    // Action descriptor does not belong to a controller of the specified type
                                    continue;
                                }
                            }

                            // An 'endpointInfo' is applicable if:
                            // 1. it has a parameter (or default value) for 'required' non-null route value
                            // 2. it does not have a parameter (or default value) for 'required' null route value
                            var isApplicable = true;
                            foreach (var routeKey in action.RouteValues.Keys)
                            {
                                if (!MatchRouteValue(action, endpointInfo, routeKey))
                                {
                                    isApplicable = false;
                                    break;
                                }
                            }

                            if (!isApplicable)
                            {
                                continue;
                            }

                            conventionalRouteOrder = CreateEndpoints(
                                endpoints,
                                ref patternStringBuilder,
                                action,
                                conventionalRouteOrder,
                                endpointInfo.ParsedPattern,
                                endpointInfo.MergedDefaults,
                                endpointInfo.Defaults,
                                endpointInfo.Name,
                                endpointInfo.DataTokens,
                                endpointInfo.ParameterPolicies,
                                suppressLinkGeneration: false,
                                suppressPathMatching: false,
                                endpointInfo.Conventions);
                        }
                    }
                    else
                    {
                        var conventionBuilder = ResolveActionConventionBuilder(action);
                        if (conventionBuilder == null)
                        {
                            // No convention builder for this action
                            // Do not create an endpoint for it
                            continue;
                        }

                        var attributeRoutePattern = RoutePatternFactory.Parse(action.AttributeRouteInfo.Template);

                        CreateEndpoints(
                            endpoints,
                            ref patternStringBuilder,
                            action,
                            action.AttributeRouteInfo.Order,
                            attributeRoutePattern,
                            attributeRoutePattern.Defaults,
                            nonInlineDefaults: null,
                            action.AttributeRouteInfo.Name,
                            dataTokens: null,
                            allParameterPolicies: null,
                            action.AttributeRouteInfo.SuppressLinkGeneration,
                            action.AttributeRouteInfo.SuppressPathMatching,
                            conventionBuilder.Conventions);
                    }
                }

                // See comments in DefaultActionDescriptorCollectionProvider. These steps are done
                // in a specific order to ensure callers always see a consistent state.

                // Step 1 - capture old token
                var oldCancellationTokenSource = _cancellationTokenSource;

                // Step 2 - update endpoints
                _endpoints = endpoints;

                // Step 3 - create new change token
                _cancellationTokenSource = new CancellationTokenSource();
                _changeToken             = new CancellationChangeToken(_cancellationTokenSource.Token);

                // Step 4 - trigger old token
                oldCancellationTokenSource?.Cancel();
            }
        }
    public void RequireAuthorization_Default()
    {
        // Arrange
        var builder = new TestEndpointConventionBuilder();

        // Act
        builder.RequireAuthorization();

        // Assert
        var convention = Assert.Single(builder.Conventions);

        var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

        convention(endpointModel);

        var authMetadata = Assert.IsAssignableFrom <IAuthorizeData>(Assert.Single(endpointModel.Metadata));

        Assert.Null(authMetadata.Policy);
    }
Ejemplo n.º 30
0
        public void RequireHost_HostNames()
        {
            // Arrange
            var builder = new TestEndpointConventionBuilder();

            // Act
            builder.RequireHost("contoso.com:8080");

            // Assert
            var convention = Assert.Single(builder.Conventions);

            var endpointModel = new RouteEndpointBuilder((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);

            convention(endpointModel);

            var hostMetadata = Assert.IsType <HostAttribute>(Assert.Single(endpointModel.Metadata));

            Assert.Equal("contoso.com:8080", hostMetadata.Hosts.Single());
        }