《ASP.NET本質論》MVC處理程序

        在ASP.NET MVC2 下,引入了 Controller 的概念,請求將被首先路由到 Controller 進行處理,然後由Controller 分配到相應的 Action完成實際的處理工作。處理的數據結果就是所謂的 Modal 。然後,這個Modal 被傳遞給View轉換成顯示的界面元素,最終發送到客戶端完成處理任務。
  在ASP.NET MVC2 下,整個MVC的路由中心也是一個處理程序,由這個處理程序再通過一個控制器的工廠來取得實際的 Controller,開始處理工作。默認情況下,這個處理程序的類型是 MvcRouteHandler ,這個處理程序可以在 routes.MapRoute 方法中指定。例如 ,默認的 MVC 設置如下所示:

routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

MVC的路由接口 ITouteHandler
        在ASP.NET中,起着路由作用的處理程序不是一個普通的處理程序,因爲對於MVC的請求來說根本不是通過請求的擴展名來判斷的,所以,這個處理程序通過一個類型爲UrlRoutingModule 的Module配置在網站中,通過HttpApplication的事件管道得到這個處理程序。
      在ASP.NET MVC中,路由處理程序必須實現接口 IRouteHandler。 IRouteHandler 定義在命名空間 System.Web.Routing 下,定義了一個獲取MVC處理程序的方法 GetHttpHandler。代碼如下所示:
 public interface IRouteHandler
    {
        IHttpHandler GetHttpHandler( RequestContext requestContext);
    }

默認情況下,ASP.NET MVC2 使用MvcRouteHandler 這個處理程序,RouteCollection還提供了Add方法 ,可以通過提供一個Route類型的參數指定特定的路由處理程序。設置的方法如下:
 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.Add(new Route("Catagory/{action}/{categoryName}",new CategoryTouteHandler()));
        }

自定義的IRouteHandler
         下面,我們實現一個能夠顯示當前路由表的路由處理程序。如果用戶請求地址的最後爲(?routeinfo),那麼,將返回一個匹配當前路由的描述。
          首先是類的定義,這個類必須實現接口 IRouteHandler,在GetHttpHandler中,我們檢查當前請求是否以 ?routeinfo 結束。如果是的話,調用自定義的方法返回當前的路由描述串,否則,通過默認的MvcRouteHandler 返回控制器。 參考代碼:

public class ShowRouteHandler:IRouteHandler
    {
        static readonly Regex regex = new Regex(@"^\?routeinfo{1}quot;,RegexOptions.IgnoreCase);

        #region IRouteHandler Members

        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            if (regex.IsMatch(requestContext.HttpContext.Request.Url.Query))
            {
                OutputReouteTable(requestContext);
            }
            IRouteHandler handler = new MvcRouteHandler();
            return handler.GetHttpHandler(requestContext);
        }

        #endregion

        private void OutputReouteTable(RequestContext requestContext)
        {
            HttpResponseBase response = requestContext.HttpContext.Response;
            System.Web.Routing.RouteData data = requestContext.RouteData;
            Table table = new Table();

            foreach (Route route in RouteTable.Routes)
            {
                TableRow row = new TableRow();
                table.Rows.Add(row);
                TableCell cell = new TableCell();
                row.Cells.Add(cell);
                Label lbl = new Label();
                lbl.Text = route.Url;
                cell.Controls.Add(lbl);
                if (route.GetRouteData(requestContext.HttpContext) != null)
                {
                    lbl.ForeColor = System.Drawing.Color.Black;
                }
                else
                {
                    lbl.ForeColor = System.Drawing.Color.Gray;
                }
                HtmlTextWriter writer = new HtmlTextWriter(response.Output);
                table.RenderControl(writer);
                response.End();
            }
        }
    }

  註冊路由處理程序
            在Global.asax的RegisterToutes方法中,使用自定義的路由處理程序替換默認的路由處理程序。代碼如下所示:
public static void RegisterRoutes(RouteCollection routes)
        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            /*
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
            */
            RouteTable.Routes.Add(
                new Route(

                    "{controller}/{action}/{id}",
                    new RouteValueDictionary(
                        new { Action="Index",id=(string)null}),
                    new ShowRouteHandler()
                        )
                );
        }


獲取控制器的工廠接口  IControllerFactory
      在ASP.NET MVC2 中,獲取控制器的工廠接口爲 IControllerFactory,這個接口定義在命名空間System.Web.Mvc下,具體的定義如下:
public interface IControllerFactory
{ 
    IController CreateController(RequestContext requestContext,string controllerName);
    void ReleaseController(IController controller);
}

默認情況下,我們使用定義在命名空間System.Web.Mvc 下的 DefaultControllerFactory
實現。這個類的定義如下:
public class DefaultControllerFactory : IControllerFactory

MVC 請求的處理過程

處理步驟

說明

當網站應用程序收到第一次請求的時候實施路由

在Global.asax中,將Route對象添加到RouteTable對象中

UrlRoutingModule使用第一個匹配的Route對象創建RouteData參數對象,然後創建RequestContext對象

創建MVC路由處理對象

MvcRouteHandler對象創建一個MvcHandler類的對象實例

創建控制器

MvcHandler對象通過IControllerFactory對象,一般使用DefaultControllerFactory 這個實現類創建控制器對象的實例

執行控制器

MvcHandler調用控制器的Execute方法

調用Action

Controller檢查被調用的Action,然後執行Action方法

處理返回結果

Action方法接受用戶的輸入參數,處理後得到準備顯示的數據,通過返回一個ViewResultRedirectResultContentResultJsonResultFileResultEmptyResult




資源處理程序
        資源處理程序 AssemblyResourceLoader運行程序員通過HTTP訪問嵌入在網站程序集中的資源,例如:script腳本、圖片或者數據文件等。
       AssemblyResourceLoader 通過 GetWebResourceUrl 方法得到一個嵌入資源的地址,通過這個地址,瀏覽器可以通過請求得到嵌入的資源。具體資源地址通過請求參數傳遞給AssemblyResourceLoader,地址形式如下:
    WebResource.axd?d=<encrypted identifier>&t=<time stamp value>
        參數中的 <encrypted identifier> 用來唯一標識這個嵌入的Web資源, <time stamp value>是一個時間戳,當程序集發生變化的時候可以被檢測出來,以使緩衝的資源失效。
       資源的處理程序配置
       資源處理程序已經在系統的web.config中進行了配置,可以直接在程序集中使用,代碼如下所示:

   <add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True" />

定義嵌入的資源
     參見:http://support.microsoft.com/kb/910445/zh-cn
     WebResourceAttribute標籤必須附加在嵌入資源的程序集中。WebResourceAttribute標籤用來說明嵌入在程序集中的資源。它接受兩個參數:一個嵌入資源的名稱,另一個是資源的MIME類型。
      資源的名稱並不一定是資源的文件名,這個名稱是由資源所在的命名空間加上資源文件名組成,如果一個文件在一個文件夾中,相當於增加了一層與文件夾同名的命名空間。註冊和使用的時候,都是以資源名稱爲準的。

獲取資源的地址
       如果需要在HTTP中使用嵌入的資源,必須獲取嵌入資源的地址,這可以通過ClientScriptManager 對象的方法 GetWebResourceUrl 得到。通常我們通過頁面對象的ClientScritp屬性來得到這個對象,方法的定義如下所示:

public string GetWebResourceUrl(
	Type type,
	string resourceName
)

其中type表示資源在的的程序集中定義的某個對象類型,resourceName表示資源的名稱。
       GetWebResourceUrl方法返回一個沒有經過編碼的URL地址,使用這個地址可以得到嵌入在網站程序集的資源,資源可以是腳本、圖片或者任何靜態的文件。


禁止的處理程序
       對於Web服務器上的一些資源,是不允許客戶端直接請求獲取的,例如,網站的配置文件、App_Code文件夾中的代碼文件等。
      對於不允許客戶端獲取的文件,可以將這些請求的處理程序映射到一個特殊的處理程序來解決,這個處理程序簡單地返回一個禁止訪問的迴應即可。在ASP.NET中這個處理程序的類型是 HttpForbiddenHandler
        HttpForbiddenHandler 直接返回一個狀態碼爲 403 的HTTP迴應,來表示訪問被拒絕。可以使用它來禁止所希望禁止的任何請求,在系統的web.config中,已經將項目文件、代碼文件以及其他類型被禁止客戶端訪問的文件映射到了這個處理程序。
 <add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
            <add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
            <add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
            <add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />

也可以自定義增加 ,比如增加一個禁止訪問Excel 

  <add path="*.xls" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />


虛擬路徑提供器

        定義虛擬路徑提供器
       默認情況下,我們在網站文件夾中加入一個aspx頁面模板文件,就可以通過客戶端的瀏覽器進行訪問,看到生成的HTML。在這個過程中,網站應用程序又是如何找到這個aspx模板文件的呢?
        在ASP.NET網站應用程序中,網站應用程序中的資源可以分爲兩類,一類是固定定位的,另一類是可通過虛擬目錄動態訪問的。
        第一類的資源都是必須保存在固定位置,使用固定命名規則的資源:

Global.asas,全局應用程序類

Web.config,網站配置文件

使用XmlSiteMapProvide 的站點地圖文件
bin文件夾下面的程序集,App_Code文件夾下面的代碼文件,全局資源文件夾App_GlobalResources下面的資源,任何的本地資源App_LocalResources
App_Data,網站應用程序的數據文件夾


      第二類資源是通過虛擬目錄訪問的資源。包括以下的類型:

ASP.NET頁面、母板頁、用戶空,一起其他生成的對象

標準的Web資源,例如,擴展名爲.htm和.jpg的資源等
任何映射到BuildProvider實例的自定義擴展
在App_Theme文件夾中的命名主題

         對於第二類資源,默認情況下是直接在網站的文件中進行定位,比如說,我們訪問網站根目錄下的default.aspx,那麼網站應用程序將在網站的根目錄下尋找這個default.aspx文件。在ASP.NET 2.0之後,通過虛擬目錄訪問的資源的過程是可以定義的。
      定義在System.Web.Hosting命名空間下的抽象基類 VirtualPathProvider定義了定位資源的約定如下:

public abstract class VirtualPathProvider : MarshalByRefObject

在網站中,虛擬目錄通過類型VirtualDirectory表示,這個類型也定義在同一命名空間下:
public abstract class VirtualDirectory : VirtualFileBase

虛擬目錄中的文件通過VirtualFile表示:
public abstract class VirtualFile : VirtualFileBase

對於VirtualFile來說,可以通過對象的Open方法獲得一個字節流,以便讀取文件的時間內容:
public abstract Stream Open()

     當現實自定義的VirtulaPathProvider的時候,必須至少實現下面列出的兩個方法:
FileExists和GetFile
     如果實現中還涉及虛擬文件系統中的目錄,那麼還必須實現關於目錄的兩個方法:
DirectoryExists 和 GetDirectory。


          註冊虛擬路徑提供器
           必須註冊自定義的VirtualPathProvider,才能在網站應用程序中使用。註冊必須在第一次通過虛擬文件系統定位資源之前進行。在 .NET 4.0之前,有兩種註冊的方法:通過Global.asax中的Application_Start事件註冊,或者通過定義在App_Code文件夾中任意類的AppInitialize靜態方法。方法的原型定義如下:

http://msdn.microsoft.com/ZH-CN/library/bhesyfec(v=VS.90)

http://support.microsoft.com/kb/910441/zh-cn


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章