private void ParseEntries(JObject input, List <RouteEntry> entries) { var basePath = ""; if (input["basePath"] is JProperty basePathProperty) { basePath = basePathProperty.Value <string>(); } if (input["paths"] is JObject paths) { foreach (var path in paths.Properties()) { foreach (var method in ((JObject)path.Value).Properties()) { var template = basePath + path.Name; var parsed = TemplateParser.Parse(template); entries.Add(new RouteEntry() { Method = HttpMethods.HasValue() ? method.Name.ToString() : null, Template = parsed, Precedence = RoutePrecedence.ComputeInbound(parsed), }); } } } }
/// <summary> /// Adds a new inbound route to the <see cref="TreeRouter"/>. /// </summary> /// <param name="handler">The <see cref="IRouter"/> for handling the route.</param> /// <param name="routeTemplate">The <see cref="RouteTemplate"/> of the route.</param> /// <param name="routeName">The route name.</param> /// <param name="order">The route order.</param> /// <returns>The <see cref="InboundRouteEntry"/>.</returns> public InboundRouteEntry MapInbound( IRouter handler, RouteTemplate routeTemplate, string routeName, int order) { if (handler == null) { throw new ArgumentNullException(nameof(handler)); } if (routeTemplate == null) { throw new ArgumentNullException(nameof(routeTemplate)); } var entry = new InboundRouteEntry() { Handler = handler, Order = order, Precedence = RoutePrecedence.ComputeInbound(routeTemplate), RouteName = routeName, RouteTemplate = routeTemplate, }; var constraintBuilder = new RouteConstraintBuilder(_constraintResolver, routeTemplate.TemplateText); foreach (var parameter in routeTemplate.Parameters) { if (parameter.InlineConstraints != null) { if (parameter.IsOptional) { constraintBuilder.SetOptional(parameter.Name); } foreach (var constraint in parameter.InlineConstraints) { constraintBuilder.AddResolvedConstraint(parameter.Name, constraint.Constraint); } } } entry.Constraints = constraintBuilder.Build(); entry.Defaults = new RouteValueDictionary(); foreach (var parameter in entry.RouteTemplate.Parameters) { if (parameter.DefaultValue != null) { entry.Defaults.Add(parameter.Name, parameter.DefaultValue); } } InboundEntries.Add(entry); return(entry); }
public void AttributeRoute_GetEntries_CreatesInboundEntry_CombinesLikeActions() { // Arrange var actions = new List <ActionDescriptor>() { new ActionDescriptor() { AttributeRouteInfo = new AttributeRouteInfo() { Template = "api/Blog/{id}", Name = "BLOG_INDEX", Order = 17, }, RouteValues = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { { "controller", "Blog" }, { "action", "Index" }, }, }, new ActionDescriptor() { AttributeRouteInfo = new AttributeRouteInfo() { Template = "api/Blog/{id}", Name = "BLOG_INDEX", Order = 17, }, RouteValues = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { { "controller", "Blog" }, { "action", "Index2" }, }, }, }; var builder = CreateBuilder(); var actionDescriptorProvider = CreateActionDescriptorProvider(actions); var route = CreateRoute(CreateHandler().Object, actionDescriptorProvider.Object); // Act route.AddEntries(builder, actionDescriptorProvider.Object.ActionDescriptors); // Assert Assert.Collection( builder.InboundEntries, e => { Assert.Empty(e.Constraints); Assert.Equal(17, e.Order); Assert.Equal(RoutePrecedence.ComputeInbound(e.RouteTemplate), e.Precedence); Assert.Equal("BLOG_INDEX", e.RouteName); Assert.Equal("api/Blog/{id}", e.RouteTemplate.TemplateText); Assert.Empty(e.Defaults); }); }
public override void AddEntry(string pattern, MatcherEndpoint endpoint) { var parsed = TemplateParser.Parse(pattern); _entries.Add(new Entry() { Order = 0, Pattern = parsed, Precedence = RoutePrecedence.ComputeInbound(parsed), Endpoint = endpoint, }); }
private static void Sort(List <RouteEntry> entries) { // We need to sort these in precedence order for the linear matchers. entries.Sort((x, y) => { var comparison = RoutePrecedence.ComputeInbound(x.Template).CompareTo(RoutePrecedence.ComputeInbound(y.Template)); if (comparison != 0) { return(comparison); } return(string.Compare(x.Template.TemplateText, y.Template.TemplateText, StringComparison.Ordinal)); }); }
public void AttributeRoute_GetEntries_CreatesInboundEntry_WithDefault() { // Arrange var actions = new List <ActionDescriptor>() { new ActionDescriptor() { AttributeRouteInfo = new AttributeRouteInfo() { Template = "api/Blog/{*slug=hello}", Name = "BLOG_INDEX", Order = 17, }, RouteValues = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { { TreeRouter.RouteGroupKey, "1" } }, RouteValueDefaults = new Dictionary <string, object>() { { "controller", "Blog" }, { "action", "Index" }, }, }, }; var builder = CreateBuilder(); var actionDescriptorProvider = CreateActionDescriptorProvider(actions); var route = CreateRoute(CreateHandler().Object, actionDescriptorProvider.Object); // Act route.AddEntries(builder, actionDescriptorProvider.Object.ActionDescriptors); // Assert Assert.Collection( builder.InboundEntries, e => { Assert.Empty(e.Constraints); Assert.Equal(17, e.Order); Assert.Equal(RoutePrecedence.ComputeInbound(e.RouteTemplate), e.Precedence); Assert.Equal("BLOG_INDEX", e.RouteName); Assert.Equal("api/Blog/{*slug=hello}", e.RouteTemplate.TemplateText); Assert.Collection( e.Defaults.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair <string, object>(TreeRouter.RouteGroupKey, "1"), kvp), kvp => Assert.Equal(new KeyValuePair <string, object>("slug", "hello"), kvp)); }); }
public int CompareTo(Entry other) { var comparison = Endpoint.Order.CompareTo(other.Endpoint.Order); if (comparison != 0) { return(comparison); } comparison = RoutePrecedence.ComputeInbound(Endpoint.ParsedTemplate).CompareTo(RoutePrecedence.ComputeInbound(other.Endpoint.ParsedTemplate)); if (comparison != 0) { return(comparison); } return(Endpoint.Template.CompareTo(other.Endpoint.Template)); }
private InboundRouteEntry MapInbound(RouteTemplate template, Endpoint[] endpoints, int order) { if (template == null) { throw new ArgumentNullException(nameof(template)); } var entry = new InboundRouteEntry() { Precedence = RoutePrecedence.ComputeInbound(template), RouteTemplate = template, Order = order, Tag = endpoints, }; var constraintBuilder = new RouteConstraintBuilder(_constraintFactory, template.TemplateText); foreach (var parameter in template.Parameters) { if (parameter.InlineConstraints != null) { if (parameter.IsOptional) { constraintBuilder.SetOptional(parameter.Name); } foreach (var constraint in parameter.InlineConstraints) { constraintBuilder.AddResolvedConstraint(parameter.Name, constraint.Constraint); } } } entry.Constraints = constraintBuilder.Build(); entry.Defaults = new RouteValueDictionary(); foreach (var parameter in entry.RouteTemplate.Parameters) { if (parameter.DefaultValue != null) { entry.Defaults.Add(parameter.Name, parameter.DefaultValue); } } return(entry); }
internal RoutePattern( string rawText, Dictionary <string, object> defaults, Dictionary <string, IReadOnlyList <RoutePatternConstraintReference> > constraints, RoutePatternParameterPart[] parameters, RoutePatternPathSegment[] pathSegments) { Debug.Assert(defaults != null); Debug.Assert(constraints != null); Debug.Assert(parameters != null); Debug.Assert(pathSegments != null); RawText = rawText; Defaults = defaults; Constraints = constraints; Parameters = parameters; PathSegments = pathSegments; InboundPrecedence = RoutePrecedence.ComputeInbound(this); OutboundPrecedence = RoutePrecedence.ComputeOutbound(this); }
internal RoutePattern( string rawText, IReadOnlyDictionary <string, object> defaults, IReadOnlyDictionary <string, IReadOnlyList <RoutePatternParameterPolicyReference> > parameterPolicies, IReadOnlyList <RoutePatternParameterPart> parameters, IReadOnlyList <RoutePatternPathSegment> pathSegments) { Debug.Assert(defaults != null); Debug.Assert(parameterPolicies != null); Debug.Assert(parameters != null); Debug.Assert(pathSegments != null); RawText = rawText; Defaults = defaults; ParameterPolicies = parameterPolicies; Parameters = parameters; PathSegments = pathSegments; InboundPrecedence = RoutePrecedence.ComputeInbound(this); OutboundPrecedence = RoutePrecedence.ComputeOutbound(this); }
private int InvokeCore() { if (!Input.HasValue() && !InputDirectory.HasValue()) { ShowHelp(); return(1); } if (Input.HasValue() && InputDirectory.HasValue()) { ShowHelp(); return(1); } if (!Output.HasValue()) { Output.Values.Add("Out.generated.cs"); } if (InputDirectory.HasValue()) { Input.Values.AddRange(Directory.EnumerateFiles(InputDirectory.Value(), "*.json", SearchOption.AllDirectories)); } Console.WriteLine($"Processing {Input.Values.Count} files..."); var entries = new List <RouteEntry>(); for (var i = 0; i < Input.Values.Count; i++) { var input = ReadInput(Input.Values[i]); ParseEntries(input, entries); } // We don't yet want to support complex segments. for (var i = entries.Count - 1; i >= 0; i--) { if (HasComplexSegment(entries[i])) { Out.WriteLine("Skipping route with complex segment: " + entries[i].Template.TemplateText); entries.RemoveAt(i); } } // The data that we're provided by might be unambiguous. // Remove any routes that would be ambiguous in our system. var routesByPrecedence = new Dictionary <decimal, List <RouteEntry> >(); for (var i = entries.Count - 1; i >= 0; i--) { var entry = entries[i]; var precedence = RoutePrecedence.ComputeInbound(entries[i].Template); if (!routesByPrecedence.TryGetValue(precedence, out var matches)) { matches = new List <RouteEntry>(); routesByPrecedence.Add(precedence, matches); } if (IsDuplicateTemplate(entry, matches)) { Out.WriteLine("Duplicate route template: " + entries[i].Template.TemplateText); entries.RemoveAt(i); continue; } matches.Add(entry); } // We're not too sophisticated with how we generate parameter values, just hoping for // the best. For parameters we generate a segment that is the same length as the parameter name // but with a minimum of 5 characters to avoid collisions. for (var i = entries.Count - 1; i >= 0; i--) { entries[i].RequestUrl = GenerateRequestUrl(entries[i].Template); if (entries[i].RequestUrl == null) { Out.WriteLine("Failed to create a request for: " + entries[i].Template.TemplateText); entries.RemoveAt(i); continue; } } Sort(entries); var text = Template.Execute(entries); File.WriteAllText(Output.Value(), text); return(0); }