예제 #1
0
    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),
                    });
                }
            }
        }
    }
예제 #2
0
        /// <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);
        }
예제 #3
0
        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);
            });
        }
예제 #4
0
            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,
                });
            }
예제 #5
0
    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));
        });
    }
예제 #6
0
        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));
            }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
    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);
    }