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); } } }
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); }
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(""); }); }