Ejemplo n.º 1
0
        /// <summary>
        /// Builds a <see cref="TreeRouter"/> with the <see cref="InboundEntries"/>
        /// and <see cref="OutboundEntries"/> defined in this <see cref="TreeRouteBuilder"/>.
        /// </summary>
        /// <param name="version">The version of the <see cref="TreeRouter"/>.</param>
        /// <returns>The <see cref="TreeRouter"/>.</returns>
        public TreeRouter Build(int version)
        {
            // Tree route builder builds a tree for each of the different route orders defined by
            // the user. When a route needs to be matched, the matching algorithm in tree router
            // just iterates over the trees in ascending order when it tries to match the route.
            var trees = new Dictionary <int, UrlMatchingTree>();

            foreach (var entry in InboundEntries)
            {
                UrlMatchingTree tree;
                if (!trees.TryGetValue(entry.Order, out tree))
                {
                    tree = new UrlMatchingTree(entry.Order);
                    trees.Add(entry.Order, tree);
                }

                AddEntryToTree(tree, entry);
            }

            return(new TreeRouter(
                       trees.Values.OrderBy(tree => tree.Order).ToArray(),
                       OutboundEntries,
                       _urlEncoder,
                       _objectPool,
                       _logger,
                       _constraintLogger,
                       version));
        }
Ejemplo n.º 2
0
        public TreeRouter Build(int version)
        {
            var trees = new Dictionary <int, UrlMatchingTree>();

            foreach (var entry in InboundEntries)
            {
                UrlMatchingTree tree;
                if (!trees.TryGetValue(entry.Order, out tree))
                {
                    tree = new UrlMatchingTree(entry.Order);
                    trees.Add(entry.Order, tree);
                }

                AddEntryToTree(tree, entry);
            }

            return(new TreeRouter(
                       trees.Values.OrderBy(tree => tree.Order).ToArray(),
                       OutboundEntries,
                       _urlEncoder,
                       _objectPool,
                       _logger,
                       _constraintLogger,
                       version));
        }
Ejemplo n.º 3
0
        public TreeRouter Build(int version)
        {
            var trees = new Dictionary <int, UrlMatchingTree>();

            foreach (var entry in _matchingEntries)
            {
                UrlMatchingTree tree;
                if (!trees.TryGetValue(entry.Order, out tree))
                {
                    tree = new UrlMatchingTree(entry.Order);
                    trees.Add(entry.Order, tree);
                }

                AddEntryToTree(tree, entry);
            }

            return(new TreeRouter(
                       _target,
                       trees.Values.OrderBy(tree => tree.Order).ToArray(),
                       _generatingEntries,
                       _logger,
                       _constraintLogger,
                       version));
        }
Ejemplo n.º 4
0
        private void AddEntryToTree(UrlMatchingTree tree, InboundRouteEntry entry)
        {
            // The url matching tree represents all the routes asociated with a given
            // order. Each node in the tree represents all the different categories
            // a segment can have for which there is a defined inbound route entry.
            // Each node contains a set of Matches that indicate all the routes for which
            // a URL is a potential match. This list contains the routes with the same
            // number of segments and the routes with the same number of segments plus an
            // additional catch all parameter (as it can be empty).
            // For example, for a set of routes like:
            // 'Customer/Index/{id}'
            // '{Controller}/{Action}/{*parameters}'
            //
            // The route tree will look like:
            // Root ->
            //     Literals: Customer ->
            //                   Literals: Index ->
            //                                Parameters: {id}
            //                                                Matches: 'Customer/Index/{id}'
            //     Parameters: {Controller} ->
            //                     Parameters: {Action} ->
            //                                     Matches: '{Controller}/{Action}/{*parameters}'
            //                                     CatchAlls: {*parameters}
            //                                                    Matches: '{Controller}/{Action}/{*parameters}'
            //
            // When the tree router tries to match a route, it iterates the list of url matching trees
            // in ascending order. For each tree it traverses each node starting from the root in the
            // following order: Literals, constrained parameters, parameters, constrained catch all routes, catch alls.
            // When it gets to a node of the same length as the route its trying to match, it simply looks at the list of
            // candidates (which is in precence order) and tries to match the url against it.
            //

            var current = tree.Root;
            var matcher = new TemplateMatcher(entry.RouteTemplate, entry.Defaults);

            for (var i = 0; i < entry.RouteTemplate.Segments.Count; i++)
            {
                var segment = entry.RouteTemplate.Segments[i];
                if (!segment.IsSimple)
                {
                    // Treat complex segments as a constrained parameter
                    if (current.ConstrainedParameters == null)
                    {
                        current.ConstrainedParameters = new UrlMatchingNode(length: i + 1);
                    }

                    current = current.ConstrainedParameters;
                    continue;
                }

                Debug.Assert(segment.Parts.Count == 1);
                var part = segment.Parts[0];
                if (part.IsLiteral)
                {
                    UrlMatchingNode next;
                    if (!current.Literals.TryGetValue(part.Text, out next))
                    {
                        next = new UrlMatchingNode(length: i + 1);
                        current.Literals.Add(part.Text, next);
                    }

                    current = next;
                    continue;
                }

                if (part.IsParameter && (part.IsOptional || part.IsCatchAll || part.DefaultValue != null))
                {
                    current.Matches.Add(new InboundMatch()
                    {
                        Entry = entry, TemplateMatcher = matcher
                    });
                }

                if (part.IsParameter && part.InlineConstraints.Any() && !part.IsCatchAll)
                {
                    if (current.ConstrainedParameters == null)
                    {
                        current.ConstrainedParameters = new UrlMatchingNode(length: i + 1);
                    }

                    current = current.ConstrainedParameters;
                    continue;
                }

                if (part.IsParameter && !part.IsCatchAll)
                {
                    if (current.Parameters == null)
                    {
                        current.Parameters = new UrlMatchingNode(length: i + 1);
                    }

                    current = current.Parameters;
                    continue;
                }

                if (part.IsParameter && part.InlineConstraints.Any() && part.IsCatchAll)
                {
                    if (current.ConstrainedCatchAlls == null)
                    {
                        current.ConstrainedCatchAlls = new UrlMatchingNode(length: i + 1)
                        {
                            IsCatchAll = true
                        };
                    }

                    current = current.ConstrainedCatchAlls;
                    continue;
                }

                if (part.IsParameter && part.IsCatchAll)
                {
                    if (current.CatchAlls == null)
                    {
                        current.CatchAlls = new UrlMatchingNode(length: i + 1)
                        {
                            IsCatchAll = true
                        };
                    }

                    current = current.CatchAlls;
                    continue;
                }

                Debug.Fail("We shouldn't get here.");
            }

            current.Matches.Add(new InboundMatch()
            {
                Entry = entry, TemplateMatcher = matcher
            });
            current.Matches.Sort((x, y) =>
            {
                var result = x.Entry.Precedence.CompareTo(y.Entry.Precedence);
                return(result == 0 ? x.Entry.RouteTemplate.TemplateText.CompareTo(y.Entry.RouteTemplate.TemplateText) : result);
            });
        }
Ejemplo n.º 5
0
        private void AddEntryToTree(UrlMatchingTree tree, InboundRouteEntry entry)
        {
            var current = tree.Root;

            var matcher = new TemplateMatcher(entry.RouteTemplate, entry.Defaults);

            for (var i = 0; i < entry.RouteTemplate.Segments.Count; i++)
            {
                var segment = entry.RouteTemplate.Segments[i];
                if (!segment.IsSimple)
                {
                    // Treat complex segments as a constrained parameter
                    if (current.ConstrainedParameters == null)
                    {
                        current.ConstrainedParameters = new UrlMatchingNode(length: i + 1);
                    }

                    current = current.ConstrainedParameters;
                    continue;
                }

                Debug.Assert(segment.Parts.Count == 1);
                var part = segment.Parts[0];
                if (part.IsLiteral)
                {
                    UrlMatchingNode next;
                    if (!current.Literals.TryGetValue(part.Text, out next))
                    {
                        next = new UrlMatchingNode(length: i + 1);
                        current.Literals.Add(part.Text, next);
                    }

                    current = next;
                    continue;
                }

                if (part.IsParameter && (part.IsOptional || part.IsCatchAll))
                {
                    current.Matches.Add(new InboundMatch()
                    {
                        Entry = entry, TemplateMatcher = matcher
                    });
                }

                if (part.IsParameter && part.InlineConstraints.Any() && !part.IsCatchAll)
                {
                    if (current.ConstrainedParameters == null)
                    {
                        current.ConstrainedParameters = new UrlMatchingNode(length: i + 1);
                    }

                    current = current.ConstrainedParameters;
                    continue;
                }

                if (part.IsParameter && !part.IsCatchAll)
                {
                    if (current.Parameters == null)
                    {
                        current.Parameters = new UrlMatchingNode(length: i + 1);
                    }

                    current = current.Parameters;
                    continue;
                }

                if (part.IsParameter && part.InlineConstraints.Any() && part.IsCatchAll)
                {
                    if (current.ConstrainedCatchAlls == null)
                    {
                        current.ConstrainedCatchAlls = new UrlMatchingNode(length: i + 1)
                        {
                            IsCatchAll = true
                        };
                    }

                    current = current.ConstrainedCatchAlls;
                    continue;
                }

                if (part.IsParameter && part.IsCatchAll)
                {
                    if (current.CatchAlls == null)
                    {
                        current.CatchAlls = new UrlMatchingNode(length: i + 1)
                        {
                            IsCatchAll = true
                        };
                    }

                    current = current.CatchAlls;
                    continue;
                }

                Debug.Fail("We shouldn't get here.");
            }

            current.Matches.Add(new InboundMatch()
            {
                Entry = entry, TemplateMatcher = matcher
            });
            current.Matches.Sort((x, y) =>
            {
                var result = x.Entry.Precedence.CompareTo(y.Entry.Precedence);
                return(result == 0 ? x.Entry.RouteTemplate.TemplateText.CompareTo(y.Entry.RouteTemplate.TemplateText) : result);
            });
        }