public void Parse_ComplexSegment_OptionalParameterFollowingPeriod_LastSegment()
        {
            // Arrange
            var template = "{p1}/{p2}.{p3?}";

            var expected = new RouteTemplate(template, new List <TemplateSegment>());

            expected.Segments.Add(new TemplateSegment());
            expected.Segments[0].Parts.Add(TemplatePart.CreateParameter("p1",
                                                                        false,
                                                                        false,
                                                                        defaultValue: null,
                                                                        inlineConstraints: null));

            expected.Segments.Add(new TemplateSegment());
            expected.Segments[1].Parts.Add(TemplatePart.CreateParameter("p2",
                                                                        false,
                                                                        false,
                                                                        defaultValue: null,
                                                                        inlineConstraints: null));
            expected.Segments[1].Parts.Add(TemplatePart.CreateLiteral("."));
            expected.Segments[1].Parts.Add(TemplatePart.CreateParameter("p3",
                                                                        false,
                                                                        true,
                                                                        null,
                                                                        null));
            expected.Parameters.Add(expected.Segments[0].Parts[0]);
            expected.Parameters.Add(expected.Segments[1].Parts[0]);
            expected.Parameters.Add(expected.Segments[1].Parts[2]);

            // Act
            var actual = TemplateParser.Parse(template);

            // Assert
            Assert.Equal <RouteTemplate>(expected, actual, new TemplateEqualityComparer());
        }
        public void InitializeEndpoints()
        {
            foreach (var action in _actions.ActionDescriptors.Items)
            {
                if (action.AttributeRouteInfo == null)
                {
                    // Check each of the conventional templates to see if the action would be reachable
                    // If the action and template 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)
                    {
                        var actionRouteValues        = action.RouteValues;
                        var endpointTemplateSegments = endpointInfo.ParsedTemplate.Segments;

                        if (MatchRouteValue(action, endpointInfo, "Area") &&
                            MatchRouteValue(action, endpointInfo, "Controller") &&
                            MatchRouteValue(action, endpointInfo, "Action"))
                        {
                            var newEndpointTemplate = TemplateParser.Parse(endpointInfo.Template);

                            for (var i = 0; i < newEndpointTemplate.Segments.Count; i++)
                            {
                                // Check if the template can be shortened because the remaining parameters are optional
                                //
                                // e.g. Matching template {controller=Home}/{action=Index}/{id?} against HomeController.Index
                                // can resolve to the following endpoints:
                                // - /Home/Index/{id?}
                                // - /Home
                                // - /
                                if (UseDefaultValuePlusRemainingSegementsOptional(i, action, endpointInfo, newEndpointTemplate))
                                {
                                    var subTemplate = RouteTemplateWriter.ToString(newEndpointTemplate.Segments.Take(i));

                                    var subEndpoint = CreateEndpoint(action, subTemplate, 0, endpointInfo);
                                    _endpoints.Add(subEndpoint);
                                }

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

                                    if (part.IsParameter && IsMvcParameter(part.Name))
                                    {
                                        // Replace parameter with literal value
                                        segment.Parts[j] = TemplatePart.CreateLiteral(action.RouteValues[part.Name]);
                                    }
                                }
                            }

                            var newTemplate = RouteTemplateWriter.ToString(newEndpointTemplate.Segments);

                            var endpoint = CreateEndpoint(action, newTemplate, 0, endpointInfo);
                            _endpoints.Add(endpoint);
                        }
                    }
                }
                else
                {
                    var endpoint = CreateEndpoint(action, action.AttributeRouteInfo.Template, action.AttributeRouteInfo.Order, action.AttributeRouteInfo);
                    _endpoints.Add(endpoint);
                }
            }
        }
Exemple #3
0
        private List <Endpoint> CreateEndpoints()
        {
            List <Endpoint> endpoints = new List <Endpoint>();

            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 = 0;

                    // Check each of the conventional templates to see if the action would be reachable
                    // If the action and template 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)
                    {
                        var actionRouteValues        = action.RouteValues;
                        var endpointTemplateSegments = endpointInfo.ParsedTemplate.Segments;

                        if (MatchRouteValue(action, endpointInfo, "Area") &&
                            MatchRouteValue(action, endpointInfo, "Controller") &&
                            MatchRouteValue(action, endpointInfo, "Action"))
                        {
                            var newEndpointTemplate = TemplateParser.Parse(endpointInfo.Template);

                            for (var i = 0; i < newEndpointTemplate.Segments.Count; i++)
                            {
                                // Check if the template can be shortened because the remaining parameters are optional
                                //
                                // e.g. Matching template {controller=Home}/{action=Index}/{id?} against HomeController.Index
                                // can resolve to the following endpoints:
                                // - /Home/Index/{id?}
                                // - /Home
                                // - /
                                if (UseDefaultValuePlusRemainingSegementsOptional(i, action, endpointInfo, newEndpointTemplate))
                                {
                                    var subTemplate = RouteTemplateWriter.ToString(newEndpointTemplate.Segments.Take(i));

                                    var subEndpoint = CreateEndpoint(
                                        action,
                                        endpointInfo.Name,
                                        subTemplate,
                                        endpointInfo.Defaults,
                                        ++conventionalRouteOrder,
                                        endpointInfo,
                                        suppressLinkGeneration: false);
                                    endpoints.Add(subEndpoint);
                                }

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

                                    if (part.IsParameter && IsMvcParameter(part.Name))
                                    {
                                        // Replace parameter with literal value
                                        segment.Parts[j] = TemplatePart.CreateLiteral(action.RouteValues[part.Name]);
                                    }
                                }
                            }

                            var newTemplate = RouteTemplateWriter.ToString(newEndpointTemplate.Segments);

                            var endpoint = CreateEndpoint(
                                action,
                                endpointInfo.Name,
                                newTemplate,
                                endpointInfo.Defaults,
                                ++conventionalRouteOrder,
                                endpointInfo,
                                suppressLinkGeneration: false);
                            endpoints.Add(endpoint);
                        }
                    }
                }
                else
                {
                    var endpoint = CreateEndpoint(
                        action,
                        action.AttributeRouteInfo.Name,
                        action.AttributeRouteInfo.Template,
                        nonInlineDefaults: null,
                        action.AttributeRouteInfo.Order,
                        action.AttributeRouteInfo,
                        suppressLinkGeneration: action.AttributeRouteInfo.SuppressLinkGeneration);
                    endpoints.Add(endpoint);
                }
            }

            return(endpoints);
        }
Exemple #4
0
        public void Configure(IApplicationBuilder app)
        {
            //We are building a url template from scratch, segment by segment, oldskool
            var segment = new TemplateSegment();

            segment.Parts.Add(
                TemplatePart.CreateLiteral("hello")
                );

            var segment2 = new TemplateSegment();

            segment2.Parts.Add(
                TemplatePart.CreateLiteral("world")
                );

            var segments = new TemplateSegment [] {
                segment,
                segment2
            };

            var template        = new RouteTemplate("hello", segments.ToList());
            var templateMatcher = new TemplateMatcher(template, new RouteValueDictionary());

            app.Use(async(context, next) => {
                await context.Response.WriteAsync("We are building routing from scratch using a template segment consisted of two parts: 'hello' and 'world'.\n\n");
                await next.Invoke();
            });

            app.Use(async(context, next) => {
                var path1 = "hello/world";
                try
                {
                    var isMatch1 = templateMatcher.TryMatch(path1, new RouteValueDictionary());
                    await context.Response.WriteAsync($"{path1} is match? {isMatch1}\n");
                }
                catch (Exception ex) {
                    await context.Response.WriteAsync($"Oops {path1}: {ex?.Message}\n\n");
                }
                finally
                {
                    await next.Invoke();
                }
            });

            app.Use(async(context, next) => {
                var path1    = "/hello/world";
                var isMatch1 = templateMatcher.TryMatch(path1, new RouteValueDictionary());
                await context.Response.WriteAsync($"{path1} is match? {isMatch1}\n");
                await next.Invoke();
            });

            app.Use(async(context, next) => {
                var path1    = "/hello/";
                var isMatch1 = templateMatcher.TryMatch(path1, new RouteValueDictionary());
                await context.Response.WriteAsync($"{path1} is match? {isMatch1}\n");
                await next.Invoke();
            });

            app.Run(async context => {
                await context.Response.WriteAsync("");
            });
        }