导航

09-009 Routing 之 TemplateRoute : INamedRouter

Posted on 2015-04-08 17:04  DotNet1010  阅读(257)  评论(0)    收藏  举报

路由模板 RouteTemplate 模板路由 TemplateRoute

RouteTemplate 肯定是模板 是对文本如“{controller}/{action}" 进行分析得到的对象。

TemplateRoute 是对模板的路由 做两件事 :RouteAsync  [最终是执行方法 生成View] 和 GetVirtualPath 【可以生成URL】

构造函数代码:

	/// <param name="target"> MvcRouteHandler 执行Action方法 </param>
		/// <param name="routeName">定义的名字 可以为空 </param>
		/// <param name="routeTemplate"> 如:{controller}/{aciton}/{id?} </param>
		/// <param name="defaults"> 通过   IDictionary 指定的默认值 </param>
		/// <param name="constraints">通过 IDictionary 指定的约束 </param>
		/// <param name="dataTokens">其它的数据 供后面的代码使用 比如 命名空间</param>
		/// <param name="inlineConstraintResolver"> 行内约束解析用 分析 "range{1,50}"  </param>
		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;

            _dataTokens = dataTokens == null ? RouteValueDictionary.Empty : new RouteValueDictionary(dataTokens);

            // Data we parse from the template will be used to fill in the rest of the constraints or
            // defaults. The parser will throw for invalid routes.
            _parsedTemplate = TemplateParser.Parse(RouteTemplate);
			// 获取行内约束
            _constraints = GetConstraints(inlineConstraintResolver, RouteTemplate, _parsedTemplate, constraints);
			// 获取默认值 模板中的  通过   IDictionary 指定的
			_defaults = GetDefaults(_parsedTemplate, defaults);

			// 用来匹配 RequestPath 和 模板 
            _matcher = new TemplateMatcher(_parsedTemplate, Defaults);
			// 用来路由 和 生成 URL 
            _binder = new  TemplateBinder( _parsedTemplate, Defaults);
        }

 路由方法:

 public async virtual Task RouteAsync([NotNull] RouteContext context)
        {
            EnsureLoggers(context.HttpContext);
            using (_logger.BeginScope("TemplateRoute.RouteAsync"))
            {
                var requestPath = context.HttpContext.Request.Path.Value;

                if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
                {
                    requestPath = requestPath.Substring(1);
                }

				// 是否能够匹配当前URL  不匹配 结束
                var values = _matcher.Match(requestPath);

                if (values == null)
                {
					// 日志代码这里去掉了 
					// If we got back a null value set, that means the URI did not match
					return;
                }

                var oldRouteData = context.RouteData;

                var newRouteData = new RouteData(oldRouteData);
                MergeValues(newRouteData.DataTokens, _dataTokens);
                newRouteData.Routers.Add(_target);
                MergeValues(newRouteData.Values, values);

				// 约束条件是否满足
                if (!RouteConstraintMatcher.Match(
                    Constraints,
                    newRouteData.Values,
                    context.HttpContext,
                    this,
                    RouteDirection.IncomingRequest,
                    _constraintLogger))
                {
                    // 日志代码这里去掉了

                    return;
                }

                try
                {
                    context.RouteData = newRouteData;

					// 这里 执行对应的方法 
					// _target 默认是  MvcRouteHandler
					await _target.RouteAsync(context);

                   
                }
                finally
                {
                    // Restore the original values to prevent polluting the route data.
                    if (!context.IsHandled)
                    {
                        context.RouteData = oldRouteData;
                    }
                }
            }
        }

 GetVirtualPath 代码:

    public virtual string GetVirtualPath(VirtualPathContext context)
        {
			// AmbientValues 环境值 比如分页路径中 具体的Page值
			var values = _binder.GetValues(context.AmbientValues, context.Values);
            if (values == null)
            {
                // We're missing one of the required values for this route.
                return null;
            }

             // 约束是否匹配 给定值
            if (!RouteConstraintMatcher.Match(Constraints,
                                              values.CombinedValues,
                                              context.Context,
                                              this,
                                              RouteDirection.UrlGeneration,
                                              _constraintLogger))
            {
                return null;
            }

            // Validate that the target can accept these values.
            var childContext = CreateChildVirtualPathContext(context, values.AcceptedValues);
            var path = _target.GetVirtualPath(childContext);
            if (path != null)
            {
                // If the target generates a value then that can short circuit.
                context.IsBound = true;
                return path;
            }
            else if (!childContext.IsBound)
            {
                // The target has rejected these values.
                return null;
            }

            path = _binder.BindValues(values.AcceptedValues);
            if (path != null)
            {
                context.IsBound = true;
            }

            return path;
        }