Ejemplo n.º 1
0
        /// <summary>Creates a route builder that can build a route matching this context.</summary>
        /// <param name="template">The route template.</param>
        /// <param name="constraintResolver">
        /// The inline constraint resolver to use, if any; otherwise, <see langword="null"/>.
        /// </param>
        /// <returns>A route builder that can build a route matching this context.</returns>
        public IDirectRouteBuilder CreateBuilder(string template, IInlineConstraintResolver constraintResolver)
        {
            DirectRouteBuilder builder = new DirectRouteBuilder(_actions, _targetIsAction);

#if ASPNETWEBAPI
            string prefixedTemplate = BuildRouteTemplate(_prefix, template);
#else
            string prefixedTemplate = BuildRouteTemplate(_areaPrefix, _controllerPrefix, template ?? String.Empty);
#endif
            ValidateTemplate(prefixedTemplate);

            if (constraintResolver != null)
            {
                TRouteDictionary defaults    = new TRouteDictionary();
                TRouteDictionary constraints = new TRouteDictionary();

                string detokenizedTemplate = InlineRouteTemplateParser.ParseRouteTemplate(prefixedTemplate, defaults,
                                                                                          constraints, constraintResolver);
                TParsedRoute parsedRoute = RouteParser.Parse(detokenizedTemplate);
                decimal      precedence  = RoutePrecedence.Compute(parsedRoute, constraints);

                builder.Defaults    = defaults;
                builder.Constraints = constraints;
                builder.Template    = detokenizedTemplate;
                builder.Precedence  = precedence;
                builder.ParsedRoute = parsedRoute;
            }
            else
            {
                builder.Template = prefixedTemplate;
            }

            return(builder);
        }
Ejemplo n.º 2
0
        internal virtual DirectRouteBuilder CreateBuilder(string template,
                                                          IInlineConstraintResolver constraintResolver)
        {
            DirectRouteBuilder builder = new DirectRouteBuilder(_actions);

            string prefixedTemplate = BuildRouteTemplate(_prefix, template);

            Contract.Assert(prefixedTemplate != null);

            if (prefixedTemplate.StartsWith("/", StringComparison.Ordinal))
            {
                throw Error.InvalidOperation(SRResources.AttributeRoutes_InvalidTemplate, template, _actionName);
            }

            if (constraintResolver != null)
            {
                builder.Defaults    = new HttpRouteValueDictionary();
                builder.Constraints = new HttpRouteValueDictionary();
                builder.Template    = InlineRouteTemplateParser.ParseRouteTemplate(prefixedTemplate, builder.Defaults,
                                                                                   builder.Constraints, constraintResolver);
                builder.ParsedRoute = HttpRouteParser.Parse(builder.Template);
                builder.Precedence  = RoutePrecedence.Compute(builder.ParsedRoute, builder.Constraints);
            }
            else
            {
                builder.Template = prefixedTemplate;
            }

            return(builder);
        }
Ejemplo n.º 3
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),
                    });
                }
            }
        }
    }
Ejemplo n.º 4
0
        /// <summary>
        /// Processes one attribute route
        /// </summary>
        /// <param name="action">Action to process</param>
        /// <returns>Route information</returns>
        private AttributeRouteInfo ProcessAttributeRoute(ControllerActionDescriptor action)
        {
            string constraint;

            action.RouteValues.TryGetValue(TreeRouter.RouteGroupKey, out constraint);
            if (string.IsNullOrEmpty(constraint))
            {
                // This can happen if an ActionDescriptor has a route template, but doesn't have one of our
                // special route group constraints. This is a good indication that the user is using a 3rd party
                // routing system, or has customized their ADs in a way that we can no longer understand them.
                //
                // We just treat this case as an 'opt-out' of our attribute routing system.
                return(null);
            }

            var template = TemplateParser.Parse(action.AttributeRouteInfo.Template);

            var info = new AttributeRouteInfo
            {
                Constraints = GetConstraints(action.AttributeRouteInfo.Template, template),
                Defaults    = GetDefaults(action, template),
                Optional    = new List <string>(),
                Order       = action.AttributeRouteInfo.Order,
                Precedence  = RoutePrecedence.ComputeOutbound(template),
            };

            _parser.Parse(template, info);

            return(info);
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
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);
            });
        }
        private static decimal Compute(string template)
        {
            DefaultInlineConstraintResolver resolver    = new DefaultInlineConstraintResolver();
            HttpRouteValueDictionary        defaults    = new HttpRouteValueDictionary();
            HttpRouteValueDictionary        constraints = new HttpRouteValueDictionary();
            string standardRouteTemplate = InlineRouteTemplateParser.ParseRouteTemplate(template,
                                                                                        defaults, constraints, new DefaultInlineConstraintResolver());
            HttpParsedRoute parsedRoute = HttpRouteParser.Parse(standardRouteTemplate);

            return(RoutePrecedence.Compute(parsedRoute, constraints));
        }
Ejemplo n.º 8
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,
                });
            }
Ejemplo n.º 9
0
        public void AttributeRoute_GetEntries_CreatesMatchingEntry_WithDefault()
        {
            // Arrange
            var actions = new List <ActionDescriptor>()
            {
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Blog/{*slug=hello}",
                        Name     = "BLOG_INDEX",
                        Order    = 17,
                    },
                    RouteConstraints = new List <RouteDataActionConstraint>()
                    {
                        new RouteDataActionConstraint(TreeRouter.RouteGroupKey, "1"),
                    },
                    RouteValueDefaults = new Dictionary <string, object>()
                    {
                        { "controller", "Blog" },
                        { "action", "Index" },
                    },
                },
            };

            var actionDescriptorProvider = CreateActionDescriptorProvider(actions);

            var handler = CreateHandler().Object;
            var route   = CreateRoute(handler, actionDescriptorProvider.Object);

            // Act
            var entries = route.GetEntries(actionDescriptorProvider.Object.ActionDescriptors);

            // Assert
            Assert.Collection(
                entries.MatchingEntries,
                e =>
            {
                Assert.Empty(e.Constraints);
                Assert.Equal(17, e.Order);
                Assert.Equal(RoutePrecedence.ComputeMatched(e.RouteTemplate), e.Precedence);
                Assert.Equal("BLOG_INDEX", e.RouteName);
                Assert.Equal("api/Blog/{*slug=hello}", e.RouteTemplate.TemplateText);
                Assert.Same(handler, e.Target);
                Assert.Collection(
                    e.TemplateMatcher.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));
                Assert.Same(e.RouteTemplate, e.TemplateMatcher.Template);
            });
        }
Ejemplo n.º 10
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));
        });
    }
Ejemplo n.º 11
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));
            });
        }
Ejemplo n.º 12
0
        public void AttributeRoute_GetEntries_CreatesLinkGenerationEntry_WithDefault()
        {
            // Arrange
            var actions = new List <ActionDescriptor>()
            {
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Blog/{*slug=hello}",
                        Name     = "BLOG_INDEX",
                        Order    = 17,
                    },
                    RouteConstraints = new List <RouteDataActionConstraint>()
                    {
                        new RouteDataActionConstraint(TreeRouter.RouteGroupKey, "1"),
                    },
                    RouteValueDefaults = new Dictionary <string, object>()
                    {
                        { "controller", "Blog" },
                        { "action", "Index" },
                    },
                },
            };

            var actionDescriptorProvider = CreateActionDescriptorProvider(actions);

            var route = CreateRoute(CreateHandler().Object, actionDescriptorProvider.Object);

            // Act
            var entries = route.GetEntries(actionDescriptorProvider.Object.ActionDescriptors);

            // Assert
            Assert.Collection(
                entries.LinkGenerationEntries,
                e =>
            {
                Assert.NotNull(e.Binder);
                Assert.Empty(e.Constraints);
                Assert.Equal(new RouteValueDictionary(new { slug = "hello" }), e.Defaults);
                Assert.Equal(RoutePrecedence.ComputeGenerated(e.Template), e.GenerationPrecedence);
                Assert.Equal("BLOG_INDEX", e.Name);
                Assert.Equal(17, e.Order);
                Assert.Equal(actions[0].RouteValueDefaults, e.RequiredLinkValues);
                Assert.Equal("1", e.RouteGroup);
                Assert.Equal("api/Blog/{*slug=hello}", e.Template.TemplateText);
            });
        }
Ejemplo n.º 13
0
        public void AttributeRoute_GetEntries_CreatesOutboundEntry_WithConstraint()
        {
            // Arrange
            var actions = new List <ActionDescriptor>()
            {
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Blog/{id:int}",
                        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.OutboundEntries,
                e =>
            {
                Assert.Single(e.Constraints, kvp => kvp.Key == "id");
                Assert.Empty(e.Defaults);
                Assert.Equal(RoutePrecedence.ComputeOutbound(e.RouteTemplate), e.Precedence);
                Assert.Equal("BLOG_INDEX", e.RouteName);
                Assert.Equal(17, e.Order);
                Assert.Equal(actions[0].RouteValueDefaults.ToArray(), e.RequiredLinkValues.ToArray());
                Assert.Equal("api/Blog/{id:int}", e.RouteTemplate.TemplateText);
            });
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Processes one attribute route
        /// </summary>
        /// <param name="action">Action to process</param>
        /// <returns>Route information</returns>
        private AttributeRouteInfo ProcessAttributeRoute(ControllerActionDescriptor action)
        {
            var template = TemplateParser.Parse(action.AttributeRouteInfo.Template);

            var info = new AttributeRouteInfo
            {
                Constraints = GetConstraints(action.AttributeRouteInfo.Template, template),
                Defaults    = GetDefaults(action, template),
                Optional    = new List <string>(),
                Order       = action.AttributeRouteInfo.Order,
                Precedence  = RoutePrecedence.ComputeOutbound(template),
            };

            _parser.Parse(template, info);

            return(info);
        }
            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));
            }
Ejemplo n.º 16
0
        private OutboundRouteEntry CreateOutboundRouteEntry(RouteEndpoint endpoint)
        {
            var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata <IRouteValuesAddressMetadata>();
            var entry = new OutboundRouteEntry()
            {
                Handler            = NullRouter.Instance,
                Order              = endpoint.Order,
                Precedence         = RoutePrecedence.ComputeOutbound(endpoint.RoutePattern),
                RequiredLinkValues = new RouteValueDictionary(routeValuesAddressMetadata?.RequiredValues),
                RouteTemplate      = new RouteTemplate(endpoint.RoutePattern),
                Data      = endpoint,
                RouteName = routeValuesAddressMetadata?.RouteName,
            };

            entry.Defaults = new RouteValueDictionary(endpoint.RoutePattern.Defaults);
            return(entry);
        }
Ejemplo n.º 17
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);
        }
Ejemplo n.º 18
0
        private OutboundRouteEntry CreateOutboundRouteEntry(
            RouteEndpoint endpoint,
            IReadOnlyDictionary <string, object> requiredValues,
            string routeName)
        {
            var entry = new OutboundRouteEntry()
            {
                Handler            = NullRouter.Instance,
                Order              = endpoint.Order,
                Precedence         = RoutePrecedence.ComputeOutbound(endpoint.RoutePattern),
                RequiredLinkValues = new RouteValueDictionary(requiredValues),
                RouteTemplate      = new RouteTemplate(endpoint.RoutePattern),
                Data      = endpoint,
                RouteName = routeName,
            };

            entry.Defaults = new RouteValueDictionary(endpoint.RoutePattern.Defaults);
            return(entry);
        }
Ejemplo n.º 19
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);
        }
Ejemplo n.º 20
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);
        }
Ejemplo n.º 21
0
        private OutboundRouteEntry CreateOutboundRouteEntry(MatcherEndpoint endpoint)
        {
            var routeNameMetadata = endpoint.Metadata.GetMetadata <IRouteNameMetadata>();
            var entry             = new OutboundRouteEntry()
            {
                Handler            = NullRouter.Instance,
                Order              = endpoint.Order,
                Precedence         = RoutePrecedence.ComputeOutbound(endpoint.ParsedTemplate),
                RequiredLinkValues = endpoint.RequiredValues,
                RouteTemplate      = endpoint.ParsedTemplate,
                Data      = endpoint,
                RouteName = routeNameMetadata?.Name,
            };

            // TODO: review. These route constriants should be constructed when the endpoint
            // is built. This way they can be checked for validity on app startup too
            var constraintBuilder = new RouteConstraintBuilder(
                _inlineConstraintResolver,
                endpoint.ParsedTemplate.TemplateText);

            foreach (var parameter in endpoint.ParsedTemplate.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    = endpoint.Defaults;
            return(entry);
        }
Ejemplo n.º 22
0
        private static RouteInfo GetRouteInfo(
            IInlineConstraintResolver constraintResolver,
            Dictionary <string, RouteTemplate> templateCache,
            ActionDescriptor action)
        {
            var constraint = action.RouteConstraints
                             .FirstOrDefault(c => c.RouteKey == TreeRouter.RouteGroupKey);

            if (constraint == null ||
                constraint.KeyHandling != RouteKeyHandling.RequireKey ||
                constraint.RouteValue == null)
            {
                // This can happen if an ActionDescriptor has a route template, but doesn't have one of our
                // special route group constraints. This is a good indication that the user is using a 3rd party
                // routing system, or has customized their ADs in a way that we can no longer understand them.
                //
                // We just treat this case as an 'opt-out' of our attribute routing system.
                return(null);
            }

            var routeInfo = new RouteInfo()
            {
                ActionDescriptor = action,
                RouteGroup       = constraint.RouteValue,
                RouteTemplate    = action.AttributeRouteInfo.Template,
            };

            try
            {
                RouteTemplate parsedTemplate;
                if (!templateCache.TryGetValue(action.AttributeRouteInfo.Template, out parsedTemplate))
                {
                    // Parsing with throw if the template is invalid.
                    parsedTemplate = TemplateParser.Parse(action.AttributeRouteInfo.Template);
                    templateCache.Add(action.AttributeRouteInfo.Template, parsedTemplate);
                }

                routeInfo.ParsedTemplate = parsedTemplate;
            }
            catch (Exception ex)
            {
                routeInfo.ErrorMessage = ex.Message;
                return(routeInfo);
            }

            foreach (var kvp in action.RouteValueDefaults)
            {
                foreach (var parameter in routeInfo.ParsedTemplate.Parameters)
                {
                    if (string.Equals(kvp.Key, parameter.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        routeInfo.ErrorMessage = Resources.FormatAttributeRoute_CannotContainParameter(
                            routeInfo.RouteTemplate,
                            kvp.Key,
                            kvp.Value);

                        return(routeInfo);
                    }
                }
            }

            routeInfo.Order = action.AttributeRouteInfo.Order;

            routeInfo.MatchPrecedence      = RoutePrecedence.ComputeMatched(routeInfo.ParsedTemplate);
            routeInfo.GenerationPrecedence = RoutePrecedence.ComputeGenerated(routeInfo.ParsedTemplate);

            routeInfo.Name = action.AttributeRouteInfo.Name;

            var constraintBuilder = new RouteConstraintBuilder(constraintResolver, routeInfo.RouteTemplate);

            foreach (var parameter in routeInfo.ParsedTemplate.Parameters)
            {
                if (parameter.InlineConstraints != null)
                {
                    if (parameter.IsOptional)
                    {
                        constraintBuilder.SetOptional(parameter.Name);
                    }

                    foreach (var inlineConstraint in parameter.InlineConstraints)
                    {
                        constraintBuilder.AddResolvedConstraint(parameter.Name, inlineConstraint.Constraint);
                    }
                }
            }

            routeInfo.Constraints = constraintBuilder.Build();

            routeInfo.Defaults = new RouteValueDictionary();
            foreach (var parameter in routeInfo.ParsedTemplate.Parameters)
            {
                if (parameter.DefaultValue != null)
                {
                    routeInfo.Defaults.Add(parameter.Name, parameter.DefaultValue);
                }
            }

            return(routeInfo);
        }
Ejemplo n.º 23
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);
    }