http://blog.csdn.net/csh624366188/article/details/7064269html
:因爲本文原在word文檔裏編寫,寫本文章時運用了大量截圖,直接複製到博客裏,沒有顯示圖片,web
圖片只是一些簡單的運行結果截圖,不影響你們學習api
p.Net MVC已經到第三版了,相信你們也都熟悉了,我也再也不重複相關概念性的東西了。可是你們必定要了解,Asp.Net MVC是微軟的一 個開源的UI層框架,是AspNet的另一種開發模式。好廢話很少說,那咱們開始進入Asp.Net MVC3 的學習中來,工欲善其事,必先利其器! 因此咱們必須搭建好本身的開發環境才能爲咱們下一步的學習和開發提供更好的支持。瀏覽器
那你的機器的必備條件是:服務器
1)VS2010(固然你非要使用VS2008那我也不能說什麼了)mvc
2)SqlServer 2000/2005/2008app
3)Asp.Net MVC3安裝包(應該是須要VS2010SP1)框架
下面提供一些URL連接方便你們下載學習:asp.net
1)Asp.Net MVC3的官網:http://www.asp.net/mvc/mvc3 ide
以下圖所示:
這個你們在安裝過程當中可能時間會很是長(>=20分鐘),你們忍耐一下!
2)安裝Asp.Net MVC3安裝包
http://www.microsoft.com/web/gallery/install.aspx?appid=MVC3
3)Asp.Net MVC3源碼開源地址:
http://aspnet.codeplex.com/releases/view/58781
以下圖所示:
第二節:第一個Asp.Net MVC3項目
1)建立項目:
2)選擇項目的默認視圖引擎
咱們選擇一個Empty模板,而後選擇Razor視圖引擎(Asp.Net MVC3中提供的新的視圖引擎)選擇HTML5標記支持打上勾(這塊我也不瞭解,呵呵,但願作過這塊研究的高手跟我分享一下!)。
3)建立後的項目:
Asp.Net MVC3貌似跟以前的版本建立的項目模板沒什麼大的不一樣,文件夾也基本類似。固然咱們看到文件夾內的Jquery的包更新到了1.5.1 。後面的文章中會對每一個文件夾都作相關的介紹。在此就很少囉嗦了。
4)添加代碼,跑起來咱們的第一個Demo
首先:在Controller文件夾上右擊,選擇添加菜單,而後選擇Controller,以下圖所示:
而後彈出對話框,將Controller命名爲HomeController,注意後面的Controller不要去掉,否則它就不會被識別爲Controller了,最後點擊添加。以下圖所示:
設計器自動爲咱們生成代碼以下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}
}
下一步咱們在Action上添加咱們須要的視圖,以下所示:
5)在前臺頁面添加咱們本身的Html標籤
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<h1>Hello! It's my first Asp.Net MVC Web!</h1>
注意:紅色爲咱們本身添加的部分
6)最終結果:
在上一篇文章Asp.Net MVC3 簡單教程(一)環境準備 中 我簡單介紹了Asp.Net MVC3項目的安裝和第一個Asp.Net MVC3項目的基本狀況。沒有詳細介紹項目中各個文件夾的做用,以及建立的第一 個頁面是怎樣運行起來的?還有好多的疑問,那在這篇文章中咱們將詳細介紹項目中各個文件夾的做用,並真的第一個項目咱們簡要介紹一下 Asp.Net MVC的URL驅動的是怎麼回事。
第一節:Asp.Net MVC3項目介紹
讓咱們先看一下,一個普通的Asp.Net MVC3項目的樣例,以下圖所示
跟WebFrom仍是有區別的,若是你已經瞭解Asp.Net MVC2的話,那就感受異常熟悉了!但仍是有些區別的。無論怎樣咱們都一一介紹一下。
頗有意思的事情是即便咱們建立一個空的MVC項目,VS也自動幫咱們建立以上圖所示的目錄,這是爲什麼呢?這是因爲MVC秉承了「約定大於配置」的思 想,咱們在使用Asp.Net MVC3開發項目時也要注意,必定要按照它的約定辦事,好比:Controller在返回Action後須要一個View 進行展現(固然是調用了View()方法時),這時候Asp.Net MVC回到Views文件夾下找到Controller名字相同的文件夾下面找到具 體的頁面進行渲染,固然若是找不到會去Shared文件夾下去找。看下錶所示的就是Asp.Net MVC3中各個文件夾的做用。
文件夾 |
做用 |
/Controllers |
存放控制器類【職責是:處理用戶的請求,指揮具體的頁面進行渲染交給客戶端】 |
/Views |
存放各個控制器對應的視圖文件,若是是Razor引擎的話那後綴是cshtml.若是使用的WebFrom的視圖引擎的話,那仍是Aspx後綴。 |
/Content |
主要存放照片、CSS、Flash等文件 |
/Scripts |
主要存放腳本文件【微軟默認給咱們提供了JQuery1.5.1的包,看來JQuery已經成爲默認的工業標準了!咱們沒有退路了,呵呵,固然我我的也很是喜歡JQuery】 |
/Models |
主要存放ViewModel類【固然這個不是嚴格這樣要求的,而是推薦你這麼作。】 |
其餘的幾個比較有意思的文件:
一個是Web.Config,另一個是Global.asax雖然咱們你們都很是熟悉,可是跟以前咱們WebFrom仍是有不少的區別的。 WebConfig文件中,配置了啓用客戶端腳本驗證、配置了System.Web.Routing、System.Web.Mvc等組件。而 Global.asax則在應用啓動的時候註冊了全局的Area【區域,後面會相信講解】、全局Filter、路由等。
第二節:Asp.Net MVC的請求處理模型
在上一篇中咱們也簡單作了個小例子,直接添加一個Controller,而後在Action上添加一個View,直接運行,而後就在咱們面前呈現了一個普通的Html頁面。那咱們詳細解釋一下這種開發方式或者說開發模型。在講解以前咱們先認識幾個概念:
Controller:控制器。在Contrller文件夾添加的以Controller結尾的類就是控制器,它的每一個方法就是一個Action。 它的職責是從Model中獲取數據,並將數據交給View,它是個指揮家的角色,它並不控制View的顯示邏輯,只是將Model的數據交給View,而 具體的怎樣展現數據那是View的職責,因此Controller跟View是一個弱耦合的狀態,並且Controller能夠任意指定具體的View進 行渲染。因此達到了UI層的代碼和實體良好的分離。
View:視圖.負責數據的展現,固然這個視圖代碼的編寫應該是更接近純淨的Html的,而View層代碼的書寫又直接跟視圖引擎解析的規則有關,因此Razor的語法跟webFrom視圖引擎的語法大相徑庭。而筆者更傾向更喜歡Razor語法的簡潔、方便。
Model:不少人把Model理解成領域模型,而MVC自己是一個表現模式,它是更傾向於UI層的一個框架,因此通常咱們指定的Model呢在使用時通常做爲ViewModel來用,可是總的MVC的思想呢,Model仍是領域相關的東西吧。
通過MVC3個模塊的瞭解分析,咱們大致也知道了Asp.Net MVC的一些基本的概念。接下來咱們分析一個完整的Http的處理過程。看下面一個圖:
客戶端發送一個Http請求,首先被咱們的IIS捕獲到,而後根據Url請求的格式,最終交給咱們的Route組件,而後它負責解析出咱們的Url 具體請求的是哪一個Controller下的哪一個Action。而後MVC通過處理調用咱們的Action執行。在Action中咱們通常會從業務的 Façade層取出數據,而後將傳輸層的數據轉換成ViewModel再交給View的視圖引擎渲染,最終生成Html的字節流寫回客戶端。
回到咱們第一個項目中的狀況是,請求:Http://localhost/Home/Index請 求過來,由Route組件解析出Controller是Home,Action是Index,則經過工廠建立一個Controller的實例,而後調用 InvokeAction方法,執行Index的方法,最終執行View()方法返回一個ViewResult實例,再調用本身的 ExcuteResult方法,將數據上下文和輸出流交給視圖引擎,而後最終渲染成Html頁面交給客戶端,最終就看到了咱們的第一個頁面。
總結一下:
Asp.Net MVC全部的請求都歸結到Action上,並且Asp.Net MVC請求--處理--響應的模型很是清晰,並且沒有WebFrom那種複雜的生命週期,整個請求處理很是明晰簡單,又迴歸到了最原始的Web開發方式,就是簡單的請求處理響應!
前言
前面兩篇寫的比較簡單,剛開始寫這個系列的時候我面向的對象是剛開始接觸Asp.Net MVC的朋友,因此寫的儘可能簡單。因此寫的沒多少技術含 量。把這些技術總結出來,而後一簡單的方式讓更多的人很好的接受這是我一直努力的方向。後面會有稍微複雜點的項目!讓咱們一塊兒期待吧!
此文我將跟你們介紹一下Asp.Net MVC3 Filter的一些用法。你會了解和學習到全局Fileter,Action Filter等經常使用用法。
第一節:Filter知識儲備
項目大一點總會有相關的AOP面向切面的組件,而MVC(特指:Asp.Net MVC,如下皆同)項目中呢Action在執行前或者執行後咱們想 作一些特殊的操做(好比身份驗證,日誌,異常,行爲截取等),而不想讓MVC開發人員去關心和寫這部分重複的代碼,那咱們能夠經過AOP截取實現,而在 MVC項目中咱們就能夠直接使用它提供的Filter的特性幫咱們解決,不用本身實現複雜的AOP了。
Asp.Net MVC提供瞭如下幾種默認的Filter:
Filter Type |
實現接口 |
執行時間 |
Default Implementation |
Authorization filter |
IAuthorizationFilter |
在全部Filter和Action執行以前執行 |
AuthorizeAttribute |
Action filter |
IActionFilter |
分別在Action執行以前和以後執行。 |
ActionFilterAttribute |
Result filter |
IResultFilter |
分別在Action Result執行以後和以前 |
ResultFilterAttribute |
Exception filter |
IExceptionFilter |
只有在filter, 或者 action method, 或者 action result 拋出一個異常時候執行
|
HandleErrorAttribute |
你們注意一點,Asp.Net MVC提供的ActionFilterAttribute默認實現了IActionFilter和 IResultFilter。而ActionFilterAttribute是一個Abstract的類型,因此不能直接使用,由於它不能實例化,因此我 們想使用它必須繼承一下它而後才能使用,下圖所示的是ActionFilterAttribute的實現:
因此咱們在實現了ActionFilterAttribute,而後就能夠直接重寫一下父類的方法以下:
public virtual void OnActionExecuted(ActionExecutedContext filterContext);//在Action執行以後執行
public virtual void OnActionExecuting(ActionExecutingContext filterContext); //在Action執行前執行
public virtual void OnResultExecuted(ResultExecutedContext filterContext);//在Result執行以後
public virtual void OnResultExecuting(ResultExecutingContext filterContext); //在Result執行以前
而後咱們就能夠直接在Action、Result執行以前以後分別作一些操做。
第二節:Action Filter實戰
光說不練假把式,那如今咱們就直接作一個例子來實際演示一下。
首先咱們添加一個普通的類,直接上代碼吧:
public class DemoActionAttributeFilter : ActionFilterAttribute
{
public string Message { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{ //在Action執行以後執行 輸出到輸出流中文字:After Action Excute xxx
filterContext.HttpContext.Response.Write(@"<br />After Action Excute" + "\t " + Message);
base.OnActionExecuted(filterContext);
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{ //在Action執行前執行
filterContext.HttpContext.Response.Write(@"<br />Before Action Excute" + "\t " + Message);
base.OnActionExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{ //在Result執行以後
filterContext.HttpContext.Response.Write(@"<br />After ViewResult Excute" + "\t " + Message);
base.OnResultExecuted(filterContext);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{ //在Result執行以前
filterContext.HttpContext.Response.Write(@"<br />Before ViewResult Excute" + "\t " + Message);
base.OnResultExecuting(filterContext);
}
}
寫完這個代碼後,咱們回到Action上,打上上面的標記以下所示:
[DemoActionAttributeFilter(Message = "action")]
public ActionResult Index()
{ //Action 執行時往輸出流寫點代碼
this.ControllerContext.HttpContext.Response.Write(@"<br />Action Excute");
return Content("Result Excut! ");
}
而後執行F5,頁面上則會顯示爲:
最終咱們看到了在Action執行以前和以後都執行了咱們的重寫的DemoActionAttributeFilter方法,Result執行先後也執行了咱們的Filter的方法。
總的執行順序是:
Action執行前:OnActionExecuting方法先執行→Action執行→OnActionExecuted方法執行 →OnResultExecuting方法執行→返回的ActionRsult中的ExcuteResult方法執行→OnResultExecuted 執行。最終顯示的效果就是如上圖所示。
感受很爽吧!呵呵!
若是咱們將此標籤打到Controller上的話,DemoActionAttributeFilter將做用到Controller下的全部的Action。例如以下代碼所示:
[DemoActionAttributeFilter(Message = "controller")]
public class HomeController : Controller
{
[DemoActionAttributeFilter(Message = "action")]
public ActionResult Index()
{
this.ControllerContext.HttpContext.Response.Write(@"<br />Action Excute");
return Content("<br/>Result Excut! ");
}
}
那就有個問題了咱們再執行顯示的頁面會有什麼狀況呢?Controller上的Filter會執行嗎?那標籤的做用會執行兩次嗎?下面是最後的執行結果以下圖所示:
結果說明:默認狀況下Action上打了DemoActionAttributeFilter 標籤後,雖然在Controller上也打上了此標 籤,但它只有Action上的標籤起做用了。Index 執行時,Filter的方法只執行了一次,而某些狀況下咱們也想讓Controller上的 FilterAttribute也執行一次DemoActionAttributeFilter
那咱們怎麼才能讓Controller上的[DemoActionAttributeFilter(Message = "controller")]也起做用呢?
答案是:咱們只需在DemoActionAttributeFilter類的定義上打上標記 [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]便可【下面類的最上面紅色 字體部分】,也就是讓其成爲能夠屢次執行的Action。代碼以下:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class DemoActionAttributeFilter : ActionFilterAttribute
{
public string Message { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />After Action Excute" + "\t " + Message);
base.OnActionExecuted(filterContext);
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />Before Action Excute" + "\t " + Message);
base.OnActionExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />After ViewResult Excute" + "\t " + Message);
base.OnResultExecuted(filterContext);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />Before ViewResult Excute" + "\t " + Message);
base.OnResultExecuting(filterContext);
}
}
而後咱們執行的效果如圖所示:
咱們看到的結果是Controller上的ActionFilter先於Action上打的標記執行。一樣Result執行ExcuteResult方法以前也是先執行Controller上的Filter標記中的OnResultExcuteing方法。
最後的執行順序是:Controller上的OnActionExecuting→Action上的OnActionExecuting→Action執行→Action上的OnActionExecuted→Controller上的OnActionExecuted
到此Action就執行完畢了,咱們看到是一個入棧出棧的順序。後面是Action返回ActionResult後執行了ExecuteResult方法,但在執行以前要執行Filter。具體順序爲:
接上面→Controller的OnResultExecuting方法→Action上的OnResultExecuting→Action返回 ActionResult後執行了ExecuteResult方法→Action上的OnResultExecuted執行→Controller上的 OnResultExecuted執行→結束
第三節:Gloable Filter實戰
又接着一個問題也來了,咱們想有些公共的方法須要每一個Action都執行如下,而在全部的Controller打標記是很痛苦的。幸虧Asp。 Net MVC3帶來了一個美好的東西,全局Filter。而怎麼註冊全局Filter呢?答案就在Global.asax中。讓咱們看如下代碼,我是如 何將上面咱們定義的DemoActionAttributeFilter 註冊到全局Filter中。上代碼:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
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
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new DemoActionAttributeFilter() { Message = "Gloable" });
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
跟普通的MVC2.0中的Global.asax的區別就是紅色部分的代碼,咱們看到代碼中我將本身定義的 DemoActionAttributeFilter的實例加入到GlobalFilters.Filters集合中,而後下面一句就是註冊全局 Filter:RegisterGlobalFilters(GlobalFilters.Filters);
這樣咱們全部的Action和Result執行先後都會調用咱們的DemoActionAttributeFilter的重寫的方法。
再次運行咱們的demo看到的結果是:
咱們看到的結果是全局的Action首先執行,而後纔是Controller下的Filter執行,最後纔是Action上的標籤執行。固然這是在 DemoActionAttributeFilter類的定義上打上標記 [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]的前提下。否則 若是 Action打上了標籤跟Controller的相同則它只會執行Action上的Filter。
總結
通過這一篇文章的介紹咱們大致瞭解了Filter的使用方法,還了解到全局Filter的用法,尤爲是當相同的Filter重複做用到同一個 Action上時,若是沒有設置可屢次執行的標籤那只有Action上的Filter執行,而Controller和全局Filter都被屏蔽掉,可是設 置可屢次執行,那首先執行全局Filter其次是Controller再次之就是Action上的Filter了。
今天寫點關於Asp.Net MVC的PipeLine。首先咱們確認一點,Asp.Net WebFrom和Asp.Net MVC是在.Net 平臺下的兩種web開發方式。其實他們都是基於Asp.Net Core的不一樣表現而已。看下面一張圖,咱們就能理解了WebForm和 Asp.Net MVC的一個關係了。
那好咱們瞭解了Asp.Net平臺下的兩種開發方式,相信你們對於WebForm的Pipeline都很是熟悉了,固然這也是你熟悉Asp.Net 開發的必經之路。而看了不少關於Asp.Net MVC的資料不多有把整個Pipeline講的很是清楚的。我暫時將本身淺陋的整理和理解總結以下,歡迎 高手拍磚!
第一階段:客戶端請求
客戶端經過瀏覽器、其餘軟件、本身編寫WebClinet、模擬HttpRequest等方法來請求一個URL。固然在 Asp.Net WebFrom下,全部的請求都是歸結到Handler上,普通的Aspx、Ascx等都是繼承自IHttpHandler接口的一些實 例,因此我總結出來:WebFrom下全部的請求都是請求的Handler【不考慮Url重寫】。而作Asp.Net MVC的項目呢,全部的請求是都歸 結到Action上,Url應該是直接請求Action。
第二階段:IIS Web服務器
當一個請求到達IIS服務器後,Windows系統的內核模塊 HTTP.SYS就能監聽到這次請求,並將這次請求的URL、IP以及端口等信息解 析出來並將此請求交給註冊的應用來處理:也就是IIS的站點。請求此時就到達了IIS,IIS【此處僅表明IIS6.0版本】就會去檢查這次請求的URL 的後綴並將相應的請求交給配置的處理後綴相應的isapi。若是是.aspx或者ascx等直接交給默認設置了此處理項的 AspNet_isapi.dll來處理,若是咱們想處理Asp.Net MVC的請求的話,咱們須要在IIS裏面設置處理*.*請求交給 AspNet_isapi.dll來處理,才能將一個普通的MVC請求的URL:Http://localhost/DemoController /DemoAction交給AspNet_Isapi.dll來處理。
第三階段:Asp.Net 運行時
此時請求到AspNet_Isapi.dll後,它負責啓動Asp.Net RunTime【如過啓動了,直接將請求交給RunTime】。 Asp.Net 運行時【HttpRuntime】此時會初始化一下HttpContext上下文,並從HttpApplicationFactory去 建立一個HttpApplication對象,並將HttpContext賦值給HttpApplication,此後HttpContext的信息就會 一直在管道內往下傳遞。
HttpApplication對象開始初始化WebConfig文件中註冊的IHttpModule,請求帶着請求信息 【HttpContext】隨着管道流過多個HttpModule【通常能夠作爲權限校驗、行爲記錄、日誌等等,就是在到達Handler以前咱們均可以 直接處理這次Http請求,甚至能夠重寫URL】,固然也會通過咱們註冊的一些自定義的IHttpModule,在.Net 4.0的machine 的 config文件中默認配置了一個URLRouteModule,這個也就是咱們普通的Asp.Net MVC項目中的路由DLL引用 【System.Web.Routing】內部的一個實現了IHttpModule接口的實例類。請求最終流向了路由組件。
第四階段:Routing組件
若是你用的是MVC 2+ .NET 3.5,則你會在你的web項目中發現UrlRoutingModule就配置在你的Web.Config。.NET 4倒是在.Net的默認配置文件中配置的。
UrlRoutingModule作了這麼幾個工做:首先他會拿着你的請求到路由表中去匹配相應的路由規則。而路由表規則的定義是在HttpApplication初始化的時候由靜態方法執行的,且看一個普通的Asp.Net MVC項目的Global.asax
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)//定義路由表規則
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // 路由名稱
"{controller}/{action}/{id}", // 帶有參數的 URL
new { controller = "Home", action = "Index", id = UrlParameter.Optional } //參數默認值
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);//註冊路由表
}
}
而路由表的規則的註冊是在 Application_Start() 方法內部,那此時請求在URLRouteModule內部到路由表中的全部規 則進行匹配,並把匹配的Controller的信息和Action的信息以及RouteData等信息都解析處理,而後將請求進一步交給:實現了 IRouteHandler【實現了IHttpHandler接口】 的一個實例,下面是IRouteHandler的源碼:
namespace System.Web.Routing
{
public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}
}
若是你想本身來實現這個接口而後在Web.Config中配置一下,那麼請求就到了你本身的自定義的RouteHandler來執行後續的請求處理 操做了。若是你使用的是默認的配置,那麼請求會傳遞到MvcRouteHandler,那麼請求f附加着HttpContext就會到達 Asp.Net MVC的處理中了。
第五階段:MvcRouteHandler建立Controller
請求到此,其實跟WebForm都是一致的,然後面纔出現了一些不一樣,此時請求才真正的進入System.Web.Mvc控制的領域內。後面全部的 東西咱們均可以直接經過源碼來介紹了,而上面的全部的請求處理只能經過反射等方式來看或者學習,然後面的內容,咱們能夠幸福的直接看源碼了。那就跟我走進 它的管道怎麼流動的吧...
接着上面講,請求到了MvcRouteHandler類,而此類的源碼以下:
namespace System.Web.Mvc
{
using System.Web.Routing;
using System.Web.SessionState;
public class MvcRouteHandler : IRouteHandler
{
private IControllerFactory _controllerFactory;
public MvcRouteHandler()
{
}
public MvcRouteHandler(IControllerFactory controllerFactory)
{
_controllerFactory = controllerFactory;
}
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}
.....
}
MvcRouteHandler的GetHttpHandler方法被URLRouteModule調用,而看上面的紅色源碼部分咱們看到,它將請求上下文交給了MVCHandler,並返回了MVCHandler。
而我查看源碼得知:MVCHandler實現了IHttpHandler,此時它的ProcessRequest方法被調用。且看MVCHandler的部分源代碼:
1 public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
2 {
3 protected internal virtual void ProcessRequest(HttpContextBase httpContext)
4 {
5 SecurityUtil.ProcessInApplicationTrust(() =>
6 {
7 IController controller;
8 IControllerFactory factory;
9 ProcessRequestInit(httpContext, out controller, out factory);//初始化了ControllerFactory
10 try
11 {
12 controller.Execute(RequestContext);
13 }
14 finally
15 {
16 factory.ReleaseController(controller);
17 }
18 });
19 }
20 }
從源碼中咱們得知:請求交給MVCHandler後,它首先從ControllerBuilder獲取到當前的實現了 IControllerFactory接口的ControllerFactory【也能夠本身定義相關的 CustomerControllerFactory,而後在Glable中註冊使用】。而後根據上下文中請求的Controller的字符串信息建立出 實現了IController接口的控制器。而後調用了上面代碼中紅色部分,也就是 controller.Execute(RequestContext);那此時請求就交給了controller。
第六階段:Controller調用Action返回ActionResult
因爲此文過長,並且時間已經到了凌晨。源碼我就不貼了,簡單介紹一下流程,後面再作詳細贅述。
Controller的Execute方法是在基類ControllerBase中的方法,而此方法又調用ExecuteCore方法,而後此方法內部執行以下代碼:
string actionName = RouteData.GetRequiredString("action");
if (!ActionInvoker.InvokeAction(ControllerContext, actionName))
{
HandleUnknownAction(actionName);
}
首先從RouteData中獲取Action的名字,而後調用ActonInvoker的InvokeAction方法,調用Action執行。 Action的返回的ActionResult的ExecuteResult(controllerContext)方法被執行,那此時就出現了分叉。如 果直接返回的非ViewResult的話,那就直接協會到Respose流了返回客戶端了,若是是ViewResult的話,那就進入View的領域了。
第七階段:View視圖加載成Page類,並Render成Html
21 public override void ExecuteResult(ControllerContext context)
22 {
23 if (context == null)
24 {
25 throw new ArgumentNullException("context");
26 }
27 if (String.IsNullOrEmpty(ViewName))
28 {
29 ViewName = context.RouteData.GetRequiredString("action");
30 }
31 ViewEngineResult result = null;
32 if (View == null)
33 {
34 result = FindView(context);
35 View = result.View;
36 }
37 TextWriter writer = context.HttpContext.Response.Output;
38 ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer);
39 View.Render(viewContext, writer);
40 if (result != null)
41 {
42 result.ViewEngine.ReleaseView(context, View);
43 }
44 }
內部主要是經過ViewResult的FindView方法經過ViewEngine去加載具體的Aspx頁面或者是cshtml頁面生成對應的 page類【針對Aspx】,而後再調用IView接口的Render方法將請求信息+ViewData的信息以等一塊渲染成Html並寫回到客戶端。
在此階段咱們發現IViewEngine內部的實現這是到規定路徑下去加載Aspx頁面生成對應的ViewPage類。
IView接口的Render方法纔是真正的去將Html和數據裝配的到一塊。自此請求結束。
總結:
客戶端請求→路由器→IIS服務器內核模塊 HTTP.SYS→IIS→AspNet_isapi.dll→Asp.Net Runtime→Application→IHttpModule....IHttpModule→MVCRouteModule→MVCRouteHandler→MVCHandler→ControllerFactory
→Controller→ActionInvoke→Aciton→ActiongResult.ExcuteReuslt()【若是是ViewResult】→IViewEngine FindView→IView Render→Response
最後附兩張關於此請求管道的兩張圖,以饗讀者。
引子
本文將主要演示怎麼將多個Asp.Net MVC項目部署到一個IIS站點中的例子,主要使用的是Asp.Net MVC提供的區域的功能。
Asp.Net MVC提供了區域的功能,能夠很方便的爲大型的網站劃分區域。可讓咱們的項目不至於太複雜而致使管理混亂,有了區域後,每一個模塊 的頁面都放入相應的區域內進行管理很方便。而隨着項目的複雜,每一個開發人員開發的模塊呢也多是一個完整的解決方案,而他要開發的UI項目呢只是主站點項 目的一個區域,而若是把全部的UI項目放到一個UI項目,在團隊開發時就不很方便了,而咱們想達到的效果是:每一個模塊都對應一個UI項目【這裏指 Asp.Net MVC項目】,最後部署的時候將子項目都配置成區域,而總的項目就是一個站點。
1、項目建立
首先建立一個主Asp.Net MVC項目,而後建立一個子Asp。Net MVC項目。項目的結構以下:
注:
一、AreasDemo【子項目,做爲主項目的一個Area】、MvcAppMain【主Web項目】都是普通的Asp.Net MVC3項目
二、MVCControllers是一個類庫項目
三、補充:Asp.Net MVC的控制器:Controller是能夠放到站點的任何DLL中的,它在搜索控制器時,會搜索站點下的全部DLL, 當類符合條件:不是靜態類,類名以Controller結尾,實現了Controller基類【其實最主要是IController接口】的條件時它就會 被識別爲控制器。因此咱們能夠把控制器放到任何的其餘項目中,只有將此控制器所在的DLL拷貝到、主站點的Bin目錄或者對應的DLL目錄就能夠了。固然 也能夠放在默認的Web項目中的Controller文件夾下。
2、添加測試的Controller和Action
在子區域Web項目AreasDemo項目中添加一個Action,而後添加一個對應的視圖
在主Web項目MvcAppMain中添加一個HomeController和相應的Index.cshtml視圖文件。
在MVCAppMain項目中添加一個Admin區域,作測試使用。
項目最終截圖爲:
咱們看到,在主站點裏添加了一個Admin區域後,默認建立了一個Areas文件夾,並且內部就是存放區域項目的頁面。
3、在子項目中添加Areas Registration類
打開AreasDemo項目,添加一個AreasDemoRegistration類文件,其代碼以下:
1 public class AreasDemoRegistration : AreaRegistration//在主站點註冊區域
2 {
3 public override string AreaName
4 {
5 get { return "AreasDemo"; }
6 }
7 public override void RegisterArea(AreaRegistrationContext context)
8 {
9 context.MapRoute(
10 "AreasDemo_default",//路由名字,必須惟一
11 "AreasDemo/{controller}/{action}/{id}",//路由規則
12 new { action = "Index", id = UrlParameter.Optional }//默認值
13 );
14 }
15 }
其實就是一個普通的類,它實現了AreaRegistration基類。而後咱們註冊區域路由就會在Global.asax的Application_Start事件方法中去執行註冊到主站點的路由表中。具體
能夠參考Global.asax中紅色代碼部分:
16 protected void Application_Start()
17 {
18 AreaRegistration.RegisterAllAreas();//註冊全部區域
19 RegisterGlobalFilters(GlobalFilters.Filters);
20 RegisterRoutes(RouteTable.Routes);
21 }
至此咱們基本的測試的基礎工做都作好了,下面就是到了部署階段了。
4、部署咱們的項目
首先,咱們須要將子項目的引用到主項目中。而後咱們發佈主項目到一個磁盤文件夾。而後,將子項目AreasDemo的Views文件夾拷貝到主項目 發佈後的文件夾對應的Areas\AreasDemo文件夾下。其中AreasDemo是areaname,此文件夾須要咱們本身手動建立。而後,觀察發 布後的bin目錄下有沒有AreasDemo.dll動態連接庫【Web子項目】。
而後,咱們將此文件夾發佈爲IIS裏的一個網站。最終演示效果爲:
注:這是默認主Web的inde頁面
注:這是主站點裏添加的Admin區域
注:這是子項目action請求返回的頁面
原文出處:點擊打開連接