上一篇說的是asp.net mvc核心UseMvc的過程,末尾想捋一下asp.net核心的路由流轉過程,現在看來還是要準備下一個代碼,熟悉了代碼,那麼整個流轉過程就通了〜 不多說,今兒先看下,RouteContext: private RouteData _routeData; public Rou ...
上一篇說的是asp.net mvc核心UseMvc的過程,末尾想捋一下asp.net核心的路由流轉過程,現在看來還是要準備下一個代碼,熟悉了代碼,那麼整個流轉過程就通了〜
不多說,今兒先看下,RouteContext:
private RouteData _routeData; public RouteContext(HttpContext httpContext) { HttpContext = httpContext; RouteData = new RouteData(); } public RequestDelegate Handler { get; set; } public HttpContext HttpContext { get; } public RouteData RouteData { get { return _routeData; } set { if (value == null) { throw new ArgumentNullException(nameof(RouteData)); } _routeData = value; } }
這裡可以理解RouteContext(路由子網)就是路由的環境。
其中包含三個屬性器,RouteData,RequestDelegate與HttpContext。
那麼什麼時候設置路由的某些呢呢?
個人理解是,實在端端執行委托時,根據我們設置的路由處理程式來設置路先來看下RouteData,
private RouteValueDictionary _dataTokens; private List<IRouter> _routers; private RouteValueDictionary _values; public RouteValueDictionary DataTokens { get { if (_dataTokens == null) { _dataTokens = new RouteValueDictionary(); } return _dataTokens; } } public IList<IRouter> Routers { get { if (_routers == null) { _routers = new List<IRouter>(); } return _routers; } } public RouteValueDictionary Values { get { if (_values == null) { _values = new RouteValueDictionary(); } return _values; } }
繼續分解來看。
RouteValueDictionary DataTokens自定義傳值,但不參與路由匹配。
RouteValueDictionary Values 匹配路由中的參數。
以上兩者的區別在於是否參與匹配路由中的參數
RouteValueDictionary繼承自IDictionary,IReadOnlyDictionary。
IList <IRouter>路由器:是參與成功匹配請求的路由的列表。
Route類作業IRouter介面的實現,使用路由模板的語法定義模式,在調用RouteAsync時匹配的URL路徑。調用GetVirtualPath時,Route使用同一路由模板生成訪問路徑。換句話說,Route時Asp.Net Core的核心創造者。
繼續往下翻代碼route.cs:
public string RouteTemplate => ParsedTemplate.TemplateText; protected override Task OnRouteMatched(RouteContext context) { context.RouteData.Routers.Add(_target); return _target.RouteAsync(context); } protected override VirtualPathData OnVirtualPathGenerated(VirtualPathContext context) { return _target.GetVirtualPath(context); }
OnRouteMatched方法,我們在創建路由對象時,需要建立一個路由器對象,通過該方法後,重新寫入RouteData的Routers屬性中 RouteData的Routers屬性中,然後執行 RouteAsync方法。
public virtual Task RouteAsync(RouteContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } EnsureMatcher(); EnsureLoggers(context.HttpContext); var requestPath = context.HttpContext.Request.Path; if (!_matcher.TryMatch(requestPath, context.RouteData.Values)) { // If we got back a null value set, that means the URI did not match return Task.CompletedTask; } // Perf: Avoid accessing dictionaries if you don't need to write to them, these dictionaries are all // created lazily. if (DataTokens.Count > 0) { MergeValues(context.RouteData.DataTokens, DataTokens); } if (!RouteConstraintMatcher.Match( Constraints, context.RouteData.Values, context.HttpContext, this, RouteDirection.IncomingRequest, _constraintLogger)) { return Task.CompletedTask; } _logger.RequestMatchedRoute(Name, ParsedTemplate.TemplateText); return OnRouteMatched(context); }
private void EnsureMatcher() { if (_matcher == null) { _matcher = new TemplateMatcher(ParsedTemplate, Defaults); } }
TemplateM atcher類暫時不做過多的說明,只要知道時分析路徑並匹配
RouteTemplate。(後續再看)
看到這裡終於看到點路由相關的東西,通過RouteAsync我們1>確定路徑與路由規則匹配; 2>通過路由模板匹配路徑上的參數。
下麵我們再看OnVirtualPathGenerated這個方法。
public virtual VirtualPathData GetVirtualPath(VirtualPathContext context) { EnsureBinder(context.HttpContext); EnsureLoggers(context.HttpContext); 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.HttpContext, this, RouteDirection.UrlGeneration, _constraintLogger)) { return null; } context.Values = values.CombinedValues; var pathData = OnVirtualPathGenerated(context); if (pathData != null) { // If the target generates a value then that can short circuit. return pathData; } // If we can produce a value go ahead and do it, the caller can check context.IsBound // to see if the values were validated. // When we still cannot produce a value, this should return null. var virtualPath = _binder.BindValues(values.AcceptedValues); if (virtualPath == null) { return null; } pathData = new VirtualPathData(this, virtualPath); if (DataTokens != null) { foreach (var dataToken in DataTokens) { pathData.DataTokens.Add(dataToken.Key, dataToken.Value); } } return pathData; }
方法GetVirtualPath的返回增量VirtualPathData(後續補充),
只需要知道VirtualPathData類,包含路徑與虛擬路徑的參考信息,也就是若要生成URL,請調用GetVirtualPath方法。該方法返回VirtualPathData類的實例,該類包含有關路由的信息。VirtualPath屬性包含生成的URL。
身體不太舒服,先寫到這裡,下篇繼續看這篇未解釋的代碼。