🚫 Ad Blocker Detected

Please disable your AD blocker to continue using this site. Ads help us keep the content free! please press keyboard F5 to refresh page after disabled AD blocker

請關閉廣告攔截器以繼續使用本網站。廣告有助於我們保證內容免費。謝謝! 關閉後請按 F5 刷新頁面

0%

動手DIY改造 Asp.net MVC- Route解析機制 (第26天)

Agenda

前言

UrlRoutingModule對於OnPostResolveRequestCache事件添加一個對於MVC很重要的動作,透過RouteCollection取得此次請求匹配RouteData物件.

利用此RouteData取得要使用的IHttpHandler來執行它.

1
RouteData routeData = RouteCollection.GetRouteData(context);

RouteCollection是全域路由註冊表.我們在一開始使用MapRoute註冊與之匹配ControllerAction

RouteCollection是基於RouteBase物件集合,所以它可以存放所有繼承RouteBase物件,RouteBase這個類別有一個重要的方法來取得RouteData,RouteData封裝此次Http請求的Controller,Action…等資訊

對於每個Http請求依序找尋第一個匹配路由規則

1
2
3
4
5
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

RouteData

RouteData類別中有幾個重要屬性.

  • RouteHandler:存放IRouteHandler物件(提供IHttpHander並呼叫執行物件)
  • Values: 一個字典集合,存放Key為ControllerAction,ValueURL參數值相對位置參數
  • GetRequiredString:利用傳入string參數對於Values字典取匹配名稱.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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機制

一般使用Route這個物件是使用/當作註冊對應的規則

{Controller}/{Action}Domian後用/當作分隔

第一個區塊字串被當作ControllerName

第二個區塊字串被當作ActionName

因為在Asp.net MVC透過RouteData.GetRequiredString傳入ControllerNameActionName取得相對應的值.

這次例子我們希望可以透過QueryString來製作Route對應規則

{domain}?controller=home&action=about

透過上面URL期望呼叫HomeController.About方法

廢話不多說我們來看一下這個QueryStringRoute是如何被實現

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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.

MVCRouteData.Values取得對應的資料.

使用上就可透過RouteCollection.AddRoute添加到集合中

1
2
3
4
5
6
7
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("customer",new QueryStringRoute()
{
Url = "controller&action"
});
}

Http請求就會依序找尋第一個匹配Route來執行.

小結:

透過繼承RouteBase抽象類別並實現GetRouteData方法透過返回RouteData物件對於Http請求資訊封裝到RouteData.Values字典集合.(在MVC框架中會對於Values字典中取KeyControllerAction的值.)

最後再把新建立RouteBase物件加入到全域RouteCollection中.

希望大家看完這篇後可以了解並自行擴充自己Route機制.

本次範例程式碼Git Sample(CustomerRoute Branch)

__此文作者__:Daniel Shih(石頭)
__此文地址__: https://isdaniel.github.io/Ithelp-day26/
__版權聲明__:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!

如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^