天天看點

解讀ASP.NET 5 & MVC6系列(12):基于Lamda表達式的強類型Routing實作實作原理實作步驟弊端(或Bug)同步與推薦

前面的深入了解Routing章節,我們講到了在MVC中,除了使用預設的ASP.NET 5的路由注冊方式,還可以使用基于Attribute的特性(Route和HttpXXX系列方法)來定義。本章,我們将講述一種基于Lambda表達式的強類型類型。

這種方式的基本使用示例如下:

從示例中可以看出,我們可以通過GetRoute或PostRoute等擴充方法來定義route,而且後面使用Lambda表達式來定Controller的類型和Action的方法。

注意,在這裡擷取Action的方法名,是通過委托執行該Action方法來實作的(實際上并沒有執行,而是基于此擷取該Action的MethodInfo)。

在<code>Stratup.cs</code>的<code>ConfigureServices</code>方法中配置services的時候,我們可以對MVC站點使用的核心配置檔案<code>MvcOptions</code>進行配置,其中該類有一個<code>ApplicationModelConventions</code>屬性(<code>List&lt;IApplicationModelConvention</code>&gt;)可以儲存一個<code>IApplicationModelConvention</code>接口的集合,改接口可以對MVC程式的程式模型進行管線處理,該接口的定義如下:

接口中的<code>Apply</code>方法所接收的參數類型是<code>ApplicationModel</code>,而<code>ApplicationModel</code>有兩個極其重要的内容可以供我們操作,一個是Controller模型集合,一個是各種Filter的集合,該類的定義如下:

這裡最重要的就是<code>ControllerModel</code>類,該類的執行個體上儲存了各種各樣重要而又可以操作的資訊,比如該類和相關Action上的路由定義資料,API描述資訊,路由限制等等,這些資訊都可以進行操作。

新的IApplicationModelConvention注冊方式如下:

是以我們可以利用這個方法,在合适的時機對整個MVC的程式模型做響應的調整和修改,本章節中的強類型路由就是利用這個特性來實作的。

首先定義一個強類型的路由模型<code>TypedRouteModel</code>類,該類要繼承于<code>AttributeRouteModel</code>,<code>AttributeRouteModel</code>類是基于Attribute路由的基本模型,<code>TypedRouteModel</code>類的代碼如下:

該類主要的功能是:定義支援傳入Controller類型,支援鍊式調用。

然後再定義一個繼承<code>IApplicationModelConvention</code>接口的<code>TypedRoutingApplicationModelConvention</code>類。代碼如下:

在該類中,儲存了一個靜态變量Routes,用于儲存所有以Lamda表達式方式聲明的路由,然後在現有的Controllers集合中進行查找及修改,然後替換<code>AttributeRouteModel</code>屬性,并設定響應的Http Method(如果不設定,則預設所有的方式都允許)。

在這裡,我們隻是簡單替換<code>action.AttributeRouteModel</code>,是以會導緻一些缺陷(比如一個Action隻能支援一個路由路徑,以最後一個為準),各位同學可以根據自己的能力進行優化。

優化的時候,要注意Controller上的<code>Route</code>集合儲存在<code>controller.Attributes</code>屬性上,Action上的Route集合儲存在<code>action.Attributes</code>屬性上,可以對其進行優化。

然後,在MvcOptions上,我們再為TypeRouteModel添加一些擴充方法以友善使用,代碼如下:

在上述代碼中,我們添加了一個<code>EnableTypedRouting</code>擴充方法,以便向<code>MvcOptions.ApplicationModelConventions</code>屬性上添加新的<code>TypedRoutingApplicationModelConvention</code>類型示例。

其它的擴充方法則都是用于聲明相關的route,大家注意,在最開頭的示例中,我們看到擷取action資訊的方法是通過委托調用該action方法(但沒有真正調用),但是有的方法有參數,那怎麼辦呢?為此,我們定于一個忽略參數的Param類,代碼如下:

這樣,我們為含有參數的About方法定于路由的時候,就可以這樣來定義了,代碼如下:

另外,由于TypeRouteModel裡很多方法都是可以鍊式調用,是以我們也可以通過這種方式為route指定一個名稱,示例代碼如下:

至此,整個強類型路由的功能就實作完畢了,大家在使用的時候,就多了一種選擇了。

我們看到,在上面實作<code>IApplicationModelConvention</code>接口的時候,我們隻是簡單的對<code>action.AttributeRouteModel</code>進行替換,也就是說,如果你在Action上已經了<code>Route</code>特性的話,他會把你的資訊給你覆寫掉,進而導緻你的route失效。比如,如果你定義了一個這樣的自定義路由:

然後又通過Lamda表達式又定義了強類型路由,代碼如下:

那麼,你隻能通過<code>/homepage</code>開來通路,而不能通過<code>/index</code>來通路了,因為它把你的Route給你覆寫掉了。

但是,上述Lamda表達式方式并沒有覆寫Controller上定義的Route特性定義,是以如果你在ProductsController上定義了Route特性的話,兩者就會組合在一起,例如:

那麼你的通路網址應該是<code>/product/homepage</code>,而不是<code>/homepage</code>。不過如果你在Lamda表達式方式裡的代碼,是如下這樣的話:

那你的通路網址就應該是<code>/homepage</code>了,因為該路由字元是絕對路徑<code>/homepage</code>,而不是<code>homepage</code>。

繼續閱讀