一、路由(Routing)
路由功能最初整合在ASP.NET MVC(以下簡稱MVC)中,後來被獨立出來形成了System.Web.Routing 3.5程式集。ASP.NET 4已經把Routing功能已經轉移到了System.Web 4 程式集下作為基礎服務的一部分。在使用Routing功能時,您已不再需要在web.config中註冊Module,因為UrlRoutingModule已經整合進ASP.NET 4中了,就像FormsAuthenticationModule等Module一樣(C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config 的httpModules節點)。而ASP.NET MVC 3(以下簡稱MVC3)是基於ASP.NET 4的。
在System.Web.Routing 3.5中,UrlRoutingModule通過處理PostResolveRequestCache和PostMapRequestHandler事件來配合佈建要求處理常式(IHttpHandler),而在System.Web.Routing 4中,只處理了PostResolveRequestCache事件(PostMapRequestHandler事件也處理了,但什麼都不做,但已標明到期)。
值得一提的是ASP.NET 4的HttpRequest新增加了一個RequestContext屬性,其類型正是System.Web.Routing.RequestContext。該類封裝了當前請求上下文以及RouteData。
增加了PageRouteHandler類以支援WebForm的路由功能,該類實現IRouteHandler介面。而在ASP.NET 2.0中,得自己實作類別似的IRouteHandler。
為了更方便的添加該類型的路由規則,RouteCollection類中還新增加了四個MapPageRoute的重載方法。
簡單示範一下:
1、建立一個基於.Net 4的Web Application。
2、建立Global.asa並修改Global.asa.cs的Application_Start方法
void Application_Start(object sender, EventArgs e)
{
// 以下兩種方式都可以添加路由規則,顯然MapPageRoute更方便、清晰一些
//RouteTable.Routes.Add("newRoute",new Route("TestRouting",new PageRouteHandler("~/TestRouting.aspx")));
RouteTable.Routes.MapPageRoute("newRoute"
, "RoutingTest"
, "~/RoutingTest.aspx");
}
3、建立Web表單,命名為RoutingTest.aspx。在裡面隨便輸入一些內容。
4、啟動調試(F5),輸入類似的網址:http://localhost:3232/RoutingTest
一切正常的話應該顯示出您輸入的內容。
二、IDependencyResolver和DependencyResolver
Ioc/DI(Inversion of Control / the Dependency Injection,控制反轉/依賴注入)是實現系統解耦的一大利器。.Net平台可用的DI容器有Castle Windsor、StructureMap、Autofac 、Unity等。在MVC2中我們就可以很容易的使用這些容器,MVC3在DI方面又為我們做了什麼呢?
需要清楚一點,MVC3對DI的支援並不是說它內建了類似於Autofac之類的DI容器。它只是內建了一種建立(擷取)對象的預設“方式”(DefaultDependencyResolver),這種“方式”內部其中一個途徑是通過Activator.CreateInstance(Type serviceType)來建立對象。更重要的是,它提供了一種API讓我們可以改變這種方式。這使得我們可以使用Autofac之類的DI方式來替換。
下面我們從源碼角度分析一下MVC3是如何?這種機制的。
首先看看IDependencyResolver介面,該介面正是上面所說的建立(擷取)對象的“方式”。介面有兩個方法,GetService根據Type擷取一個簡單對象,GetServices根據Type擷取一個集合對象。
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
DependencyResolver並不是IDependencyResolver介面的實現。
它有兩個私人內聯類DefaultDependencyResolver和DelegateBasedDependencyResolver,都是現實的IDependencyResolver介面;
一個DependencyResover型的私人變數_instance;
一個IDependencyResolver型的私人變數_current;
一個靜態構造方法,方法內部建立一個DependencyResolver賦給_instance變數;
一個預設構造方法,方法內部建立一個DefaultDependencyResolver賦給_current變數;
兩個唯讀類型為IDependencyResolver的屬性Current和InnerCurrent,這兩個屬性的get方法最終返回的是_instance變數——典型的單例模式;
三個InnerSetResolver重載方法和三個SetResolver重載方法。每個SetResolver只是簡單的調用對應的InnerSetResolver方法。這些方法用於設定當前的IDependencyResolver對象,並將對象賦給_current變數。
當我們需要根據某種類型比如SomeClass建立相應的對象時,我們這樣調用:DependencyResolver.Current.GetService(typeof(SomeType))。
當然,返回結合對象就這樣調用DependencyResolver.Current.GetServices(typeof(SomeType))。
預設情況下我們使用的是DefaultDependencyResolver對象,在該對象的GetService方法內部,通過調用Activator.CreateInstance(typeof(SomeType))來建立對象,而GetServices方法返回的是numerable.Empty<object>()產生的對象。
IDependencyResolver介面是建立(擷取)對象的“方式”,而SetResolver方法等則是改變這種方式的API。下面簡單分析一下這幾個方法。
1、InnerSetResolver(IDependencyResolver resolver)
該方法接受一個IDependencyResolver型參數,方法內部直接將值賦給_current變數。
2、InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
該方法接受兩個委託,第一個接受一個Type型參數返回object型對象,而第二個返回IEnumerable<object>型集合對象。
方法內部建立一個DelegateBasedDependencyResolver對象。調用DelegateBasedDependencyResolver.GetService(Type type)返回的
是getService(type)的執行結果。相應的,調用GetServices(Type type)返回的是getServices(type)的執行結果。
3、InnerSetResolver(object commonServiceLocator)
該方法接受一個object型參數,方法內部會通過反射的方式嘗試擷取方法名為"GetInstance"和"GetAllInstances",參數為Type型的兩個方法;
接著檢查方法的傳回值是否分別是object型和IEnumeralbe<object>型,如果是建立一個DelegateBasedDependencyResolver對象,兩個方法作為構造方法
參數傳入,並將對象賦給_current變數。傳回值的不匹配則拋出異常。
您可能需要CommonServiceLocator的資料:http://commonservicelocator.codeplex.com
另外,DependencyResolverExtensions類是IDependencyResolver介面的擴充方法,分別是相應方法的泛型實現。
public static class DependencyResolverExtensions
{
public static TService GetService<TService>(this IDependencyResolver resolver)
{
return (TService) resolver.GetService(typeof(TService));
}
public static IEnumerable<TService> GetServices<TService>(this IDependencyResolver resolver)
{
return resolver.GetServices(typeof(TService)).Cast<TService>();
}
}
IDependencyResolver介面的實作類別中,通常採用面板模式。內部包含一個DI容器,當調用GetService或GetServices方法時,調用DI容器相應的方法。