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); }
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); }
public OutboundRouteEntry MapOutbound( IRouter handler, RouteTemplate routeTemplate, RouteValueDictionary requiredLinkValues, string routeName, int order) { if (handler == null) { throw new ArgumentNullException(nameof(handler)); } if (routeTemplate == null) { throw new ArgumentNullException(nameof(routeTemplate)); } if (requiredLinkValues == null) { throw new ArgumentNullException(nameof(requiredLinkValues)); } var entry = new OutboundRouteEntry() { Handler = handler, Order = order, Precedence = RoutePrecedence.ComputeOutbound(routeTemplate), RequiredLinkValues = requiredLinkValues, 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); } } OutboundEntries.Add(entry); return(entry); }
private VirtualPathData GenerateVirtualPath( VirtualPathContext context, OutboundRouteEntry entry, TemplateBinder binder) { // In attribute the context includes the values that are used to select this entry - typically // these will be the standard 'action', 'controller' and maybe 'area' tokens. However, we don't // want to pass these to the link generation code, or else they will end up as query parameters. // // So, we need to exclude from here any values that are 'required link values', but aren't // parameters in the template. // // Ex: // template: api/Products/{action} // required values: { id = "5", action = "Buy", Controller = "CoolProducts" } // // result: { id = "5", action = "Buy" } var inputValues = new RouteValueDictionary(); foreach (var kvp in context.Values) { if (entry.RequiredLinkValues.ContainsKey(kvp.Key)) { var parameter = entry.RouteTemplate.GetParameter(kvp.Key); if (parameter == null) { continue; } } inputValues.Add(kvp.Key, kvp.Value); } var bindingResult = binder.GetValues(context.AmbientValues, inputValues); if (bindingResult == null) { // A required parameter in the template didn't get a value. return(null); } var matched = RouteConstraintMatcher.Match( entry.Constraints, bindingResult.CombinedValues, context.HttpContext, this, RouteDirection.UrlGeneration, _constraintLogger); if (!matched) { // A constraint rejected this link. return(null); } var pathData = entry.Handler.GetVirtualPath(context); if (pathData != null) { // If path is non-null then the target router short-circuited, we don't expect this // in typical MVC scenarios. return(pathData); } var path = binder.BindValues(bindingResult.AcceptedValues); if (path == null) { return(null); } return(new VirtualPathData(this, path)); }