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;
}
浙公网安备 33010602011771号