Пример #1
0
        /// <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;
        }
Пример #2
0
        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));
        }
Пример #3
0
 public void Add(TreeRouteLinkGenerationEntry entry)
 {
     _generatingEntries.Add(entry);
 }
Пример #4
0
 public void Add(TreeRouteLinkGenerationEntry entry)
 {
     _generatingEntries.Add(entry);
 }
Пример #5
0
 public LinkGenerationMatch(TreeRouteLinkGenerationEntry entry, bool isFallbackMatch)
 {
     _entry = entry;
     _isFallbackMatch = isFallbackMatch;
 }