예제 #1
0
        private static IDictionary <string, IRouteConstraint> GetConstraints(
            IInlineConstraintResolver inlineConstraintResolver,
            RouteTemplate parsedTemplate,
            IDictionary <string, object> constraints)
        {
            var constraintBuilder = new RouteConstraintBuilder(inlineConstraintResolver, parsedTemplate.TemplateText);

            if (constraints != null)
            {
                foreach (var kvp in constraints)
                {
                    constraintBuilder.AddConstraint(kvp.Key, kvp.Value);
                }
            }

            foreach (var parameter in parsedTemplate.Parameters)
            {
                if (parameter.IsOptional)
                {
                    constraintBuilder.SetOptional(parameter.Name);
                }

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

            return(constraintBuilder.Build());
        }
예제 #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 GetRouteDataWithConstraintsThatIsNotStringOrCustomConstraint_Throws()
        {
            // Arrange
            var dictionary = new RouteValueDictionary(new { controller = new RouteValueDictionary() });

            ExceptionAssert.Throws <InvalidOperationException>(
                () => RouteConstraintBuilder.BuildConstraints(dictionary),
                "The constraint entry 'controller' must have a string value or be of a type which implements '" +
                typeof(IRouteConstraint) + "'.");
        }
예제 #4
0
        public void GetRouteDataWithConstraintsThatIsAStringCreatesARegex()
        {
            // Arrange
            var dictionary           = new RouteValueDictionary(new { controller = "abc" });
            var constraintDictionary = RouteConstraintBuilder.BuildConstraints(dictionary);

            // Assert
            Assert.Equal(1, constraintDictionary.Count);
            Assert.Equal("controller", constraintDictionary.First().Key);

            var constraint = constraintDictionary["controller"];

            Assert.IsType <RegexRouteConstraint>(constraint);
        }
예제 #5
0
        public void GetRouteDataWithConstraintsThatIsCustomConstraint_IsPassThrough()
        {
            // Arrange
            var originalConstraint = new Mock <IRouteConstraint>().Object;

            var dictionary           = new RouteValueDictionary(new { controller = originalConstraint });
            var constraintDictionary = RouteConstraintBuilder.BuildConstraints(dictionary);

            // Assert
            Assert.Equal(1, constraintDictionary.Count);
            Assert.Equal("controller", constraintDictionary.First().Key);

            var constraint = constraintDictionary["controller"];

            Assert.Equal(originalConstraint, constraint);
        }
예제 #6
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);
        }
예제 #7
0
        [InlineData("Abc", " abc", false)]    // Matches whole (less one char)
        public void StringConstraintsMatchingScenarios(string routeValue,
                                                       string constraintValue,
                                                       bool shouldMatch)
        {
            // Arrange
            var dictionary = new RouteValueDictionary(new { controller = routeValue });

            var constraintDictionary = RouteConstraintBuilder.BuildConstraints(
                new RouteValueDictionary(new { controller = constraintValue }));
            var constraint = constraintDictionary["controller"];

            Assert.Equal(shouldMatch,
                         constraint.Match(
                             httpContext: new Mock <HttpContext>().Object,
                             route: new Mock <IRouter>().Object,
                             routeKey: "controller",
                             values: dictionary,
                             routeDirection: RouteDirection.IncomingRequest));
        }
예제 #8
0
        public TemplateRoute([NotNull] IRouter target,
                             string routeName,
                             string routeTemplate,
                             IDictionary <string, object> defaults,
                             IDictionary <string, object> constraints,
                             IDictionary <string, object> dataTokens,
                             IInlineConstraintResolver inlineConstraintResolver)
        {
            _target        = target;
            _routeTemplate = routeTemplate ?? string.Empty;
            Name           = routeName;
            _defaults      = defaults ?? new RouteValueDictionary();
            _constraints   = RouteConstraintBuilder.BuildConstraints(constraints, _routeTemplate) ??
                             new Dictionary <string, IRouteConstraint>();
            _dataTokens = dataTokens ?? new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);

            // The parser will throw for invalid routes.
            _parsedTemplate = TemplateParser.Parse(RouteTemplate, inlineConstraintResolver);
            UpdateInlineDefaultValuesAndConstraints();

            _matcher = new TemplateMatcher(_parsedTemplate);
            _binder  = new TemplateBinder(_parsedTemplate, _defaults);
        }
예제 #9
0
        /// <summary>
        /// Processes the constraints for the specified template.
        /// </summary>
        /// <param name="rawTemplate">Raw template string</param>
        /// <param name="parsedTemplate">Parsed template</param>
        /// <returns>The constraints for this route</returns>
        private IDictionary <string, object> GetConstraints(string rawTemplate, RouteTemplate parsedTemplate)
        {
            var constraintBuilder = new RouteConstraintBuilder(_constraintResolver, rawTemplate);

            foreach (var parameter in 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);
                    }
                }
            }

            var constraints = constraintBuilder.Build();

            return(_constraintsProcessor.ProcessConstraints(constraints));
        }
예제 #10
0
        public void ConstraintBuilderWithTemplateReturnsNull_OnNullOrEmptyInput(IDictionary <string, object> input)
        {
            var result = RouteConstraintBuilder.BuildConstraints(input, "{controller}");

            Assert.Null(result);
        }
예제 #11
0
        public void ConstraintBuilderReturnsNull_OnNullOrEmptyInput(IDictionary <string, object> input)
        {
            var result = RouteConstraintBuilder.BuildConstraints(input);

            Assert.Null(result);
        }
예제 #12
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);
        }
예제 #13
0
        private static IReadOnlyDictionary<string, IRouteConstraint> GetConstraints(
            IInlineConstraintResolver inlineConstraintResolver,
            string template,
            RouteTemplate parsedTemplate,
            IDictionary<string, object> constraints)
        {
            var constraintBuilder = new RouteConstraintBuilder(inlineConstraintResolver, template);

            if (constraints != null)
            {
                foreach (var kvp in constraints)
                {
                    constraintBuilder.AddConstraint(kvp.Key, kvp.Value);
                }
            }

            foreach (var parameter in parsedTemplate.Parameters)
            {
                if (parameter.IsOptional)
                {
                    constraintBuilder.SetOptional(parameter.Name);
                }

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

            return constraintBuilder.Build();
        }
예제 #14
0
        private static IDictionary<string, IRouteConstraint> GetRouteConstriants(
            IInlineConstraintResolver inlineConstraintResolver,
            string template,
            RouteTemplate parsedRouteTemplate)
        {
            var constraintBuilder = new RouteConstraintBuilder(inlineConstraintResolver, template);
            foreach (var parameter in parsedRouteTemplate.Parameters)
            {
                if (parameter.InlineConstraints != null)
                {
                    if (parameter.IsOptional)
                    {
                        constraintBuilder.SetOptional(parameter.Name);
                    }

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

            return constraintBuilder.Build();
        }
예제 #15
0
        private static TreeRouteLinkGenerationEntry CreateGenerationEntry(
            string template,
            object requiredValues,
            int order = 0,
            string name = null)
        {
            var constraintResolver = CreateConstraintResolver();

            var entry = new TreeRouteLinkGenerationEntry();
            entry.Template = TemplateParser.Parse(template);

            var defaults = new RouteValueDictionary();
            foreach (var parameter in entry.Template.Parameters)
            {
                if (parameter.DefaultValue != null)
                {
                    defaults.Add(parameter.Name, parameter.DefaultValue);
                }
            }

            var constraintBuilder = new RouteConstraintBuilder(CreateConstraintResolver(), template);
            foreach (var parameter in entry.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);
                    }
                }
            }

            var constraints = constraintBuilder.Build();

            entry.Constraints = constraints;
            entry.Defaults = defaults;
            entry.Binder = new TemplateBinder(Encoder, Pool, entry.Template, defaults);
            entry.Order = order;
            entry.GenerationPrecedence = RoutePrecedence.ComputeGenerated(entry.Template);
            entry.RequiredLinkValues = new RouteValueDictionary(requiredValues);
            entry.RouteGroup = CreateRouteGroup(order, template);
            entry.Name = name;
            return entry;
        }