UrlRoutingModule
對於OnPostResolveRequestCache
事件添加一個對於MVC很重要的動作,透過RouteCollection
取得此次請求匹配RouteData
物件.
利用此RouteData
取得要使用的IHttpHandler
來執行它.
RouteData routeData = RouteCollection.GetRouteData(context);
RouteCollection
是全域路由註冊表.我們在一開始使用MapRoute
註冊與之匹配Controller
和Action
RouteCollection
是基於RouteBase
物件集合,所以它可以存放所有繼承RouteBase
物件,RouteBase
這個類別有一個重要的方法來取得RouteData
,RouteData
封裝此次Http
請求的Controller
,Action
...等資訊
對於每個Http
請求依序找尋第一個匹配路由規則
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
在RouteData
類別中有幾個重要屬性.
RouteHandler
:存放IRouteHandler
物件(提供IHttpHander
並呼叫執行物件)Values
: 一個字典集合,存放Key為Controller
和Action
,Value
是URL
參數值相對位置參數GetRequiredString
:利用傳入string
參數對於Values
字典取匹配名稱.public class RouteData
{
private RouteValueDictionary _values = new RouteValueDictionary();
private RouteValueDictionary _dataTokens = new RouteValueDictionary();
private IRouteHandler _routeHandler;
/// <summary>
/// 使用指定的路由及路由處理常式,初始化 <see cref="T:System.Web.Routing.RouteData" /> 類別的新執行個體。
/// </summary>
/// <param name="route">此物件會定義路由。</param>
/// <param name="routeHandler">處理要求的物件。</param>
public RouteData(RouteBase route, IRouteHandler routeHandler)
{
this.Route = route;
this.RouteHandler = routeHandler;
}
/// <summary>
/// 取得自訂值集合,當 ASP.NET 路由判斷路由是否符合要求時,會將這些值傳遞至路由處理常式但不會使用。
/// </summary>
public RouteValueDictionary DataTokens
{
get
{
return this._dataTokens;
}
}
/// <summary>取得或設定代表路由的物件。</summary>
public RouteBase Route { get; set; }
/// <summary>取得或設定處理要求路由的物件。</summary>
public IRouteHandler RouteHandler
{
get
{
return this._routeHandler;
}
set
{
this._routeHandler = value;
}
}
/// <summary>取得 URL 參數值和預設路由值的集合。</summary>
public RouteValueDictionary Values
{
get
{
return this._values;
}
}
/// <summary>擷取具有指定識別項的值。</summary>
public string GetRequiredString(string valueName)
{
object obj;
if (this.Values.TryGetValue(valueName, out obj))
{
string str = obj as string;
if (!string.IsNullOrEmpty(str))
return str;
}
throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentUICulture, System.Web.SR.GetString("RouteData_RequiredValue"), new object[1]
{
(object) valueName
}));
}
}
RouteData
主要把Client
傳送Http請求資訊經解析後存放在Values
中.
RouteBase
中有個GetRouteData
方法,藉由我們的路由設定去解析當前是否匹配到路由規則,如果有就回傳一個RouteData
物件,否則回傳Null
一般使用Route
這個物件是使用/
當作註冊對應的規則
{Controller}/{Action}
在Domian
後用/
當作分隔
第一個區塊字串被當作ControllerName
第二個區塊字串被當作ActionName
因為在Asp.net MVC透過
RouteData.GetRequiredString
傳入ControllerName
或ActionName
取得相對應的值.
這次例子我們希望可以透過QueryString
來製作Route
對應規則
{domain}?controller=home&action=about
透過上面URL
期望呼叫HomeController.About
方法
廢話不多說我們來看一下這個QueryStringRoute
是如何被實現
public class QueryStringRoute : RouteBase
{
public string Url { get; set; }
private bool Match(NameValueCollection queryString, out IDictionary<string, string> variables)
{
variables = new Dictionary<string, string>();
var para = Url.Split('&');
if (!para.All(x=>queryString.AllKeys.Contains(x)))
return false;
variables = para.ToDictionary(x => x, y => queryString[y]);
return true;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
IDictionary<string, string> value;
if (Match(httpContext.Request.QueryString,out value))
{
RouteData routeData = new RouteData(this, new MvcRouteHandler());
foreach (var dict in value)
routeData.Values.Add(dict.Key,dict.Value);
return routeData;
}
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}
我們實現RouteBase
抽象類別兩個方法
GetRouteData
GetVirtualPath
其中GetRouteData
是我們主要要實作方法
Request.QueryString
這個集合封裝Http QueryString
的資訊.
首先我們先判斷此次請求QueryString
是否由傳Controller
,Action
資料過來,如果有把值填入RouteData.Values
字典集合中,反之不匹配此Route
規則就回傳NULL
.
MVC從
RouteData.Values
取得對應的資料.
使用上就可透過RouteCollection.Add
將Route
添加到集合中
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("customer",new QueryStringRoute()
{
Url = "controller&action"
});
}
Http請求就會依序找尋第一個匹配Route
來執行.
透過繼承RouteBase
抽象類別並實現GetRouteData
方法透過返回RouteData
物件對於Http
請求資訊封裝到RouteData.Values
字典集合.(在MVC框架中會對於Values
字典中取Key
為Controller
和Action
的值.)
最後再把新建立RouteBase
物件加入到全域RouteCollection
中.
希望大家看完這篇後可以了解並自行擴充自己Route
機制.
本次範例程式碼Git Sample(CustomerRoute Branch)