/// <summary> /// Creates a new <see cref="TreeRouter"/>. /// </summary> /// <param name="next">The next router. Invoked when a route entry matches.</param> /// <param name="trees">The list of <see cref="UrlMatchingTree"/> that contains the route entries.</param> /// <param name="linkGenerationEntries">The set of <see cref="TreeRouteLinkGenerationEntry"/>.</param> /// <param name="routeLogger">The <see cref="ILogger"/> instance.</param> /// <param name="constraintLogger">The <see cref="ILogger"/> instance used /// in <see cref="RouteConstraintMatcher"/>.</param> /// <param name="version">The version of this route.</param> public TreeRouter( IRouter next, UrlMatchingTree[] trees, IEnumerable <TreeRouteLinkGenerationEntry> linkGenerationEntries, ILogger routeLogger, ILogger constraintLogger, int version) { if (next == null) { throw new ArgumentNullException(nameof(next)); } if (trees == null) { throw new ArgumentNullException(nameof(trees)); } if (linkGenerationEntries == null) { throw new ArgumentNullException(nameof(linkGenerationEntries)); } if (routeLogger == null) { throw new ArgumentNullException(nameof(routeLogger)); } if (constraintLogger == null) { throw new ArgumentNullException(nameof(constraintLogger)); } _next = next; _trees = trees; _logger = routeLogger; _constraintLogger = constraintLogger; var namedEntries = new Dictionary <string, TreeRouteLinkGenerationEntry>( StringComparer.OrdinalIgnoreCase); foreach (var entry in linkGenerationEntries) { // Skip unnamed entries if (entry.Name == null) { continue; } // We only need to keep one AttributeRouteLinkGenerationEntry per route template // so in case two entries have the same name and the same template we only keep // the first entry. TreeRouteLinkGenerationEntry namedEntry = null; if (namedEntries.TryGetValue(entry.Name, out namedEntry) && !namedEntry.Template.TemplateText.Equals(entry.Template.TemplateText, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException( Resources.FormatAttributeRoute_DifferentLinkGenerationEntries_SameName(entry.Name), nameof(linkGenerationEntries)); } else if (namedEntry == null) { namedEntries.Add(entry.Name, entry); } } _namedEntries = namedEntries; // The decision tree will take care of ordering for these entries. _linkGenerationTree = new LinkGenerationDecisionTree(linkGenerationEntries.ToArray()); Version = version; }
private VirtualPathData GenerateVirtualPath(VirtualPathContext context, TreeRouteLinkGenerationEntry entry) { // 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.Template.GetParameter(kvp.Key); if (parameter == null) { continue; } } inputValues.Add(kvp.Key, kvp.Value); } var bindingResult = entry.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 = _next.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 = entry.Binder.BindValues(bindingResult.AcceptedValues); if (path == null) { return(null); } return(new VirtualPathData(this, path)); }
public void Add(TreeRouteLinkGenerationEntry entry) { _generatingEntries.Add(entry); }
public void Add(TreeRouteLinkGenerationEntry entry) { _generatingEntries.Add(entry); }
public LinkGenerationMatch(TreeRouteLinkGenerationEntry entry, bool isFallbackMatch) { _entry = entry; _isFallbackMatch = isFallbackMatch; }