導讀:
在HowToStart那帖中,我提到了ASP.NET MVC的問題 :
如果修改一次Controller的代碼,就導致ASP.NET重啟一次 , 那麼會不會很麻煩?
有時候一個項目大一點, ASP.NET啟動一次需要幾十秒, 那樣的等待真的很浪費時間.
與思歸的交談中, 他提到了HotSwap的概念. "熱插拔" - 編寫代碼後不需要重新編譯或重啟ASP.NET.
怎樣實現這個功能呢? 現在MVC的文檔很少. 只能通過Reflector去找答案了.
一個Request,從Url, 一直到了具體的 Controller , 經過了那些步驟呢?
下面列出了這個步驟的詳細:
1. Url
2. RouteTable
3. MvcRouteHandler
4. MvcHandler
5. ControllerBuilder
6. ControllerFactory
7. Controller
這個過程中, MvcRouteHandler 是串連 RouteTable 和 MvcHandler 的橋樑.
MvcHandler則根據傳遞過來的資訊, 根據某種規則, 從所有的Assembly中找到對應的Controller類
然後把類型資訊傳遞給 ControllerBuilder/ControllerFactory , 用於指定一個更具體的Controller.
(類似RuntimeEntity那篇文章說的子類化模式..)
看來, 需要對MvcHandler下手了. 而 MvcRouteHandler 則就是 MvcHandler 的 Factory.
所以同時也要編寫MvcRouteHandler的實現 :
public class HotSwapMvcRouteHandler : System.Web.Mvc.MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(System.Web.Mvc.RequestContext requestContext)
{
HotSwapMvcHandler handler = new HotSwapMvcHandler();
handler.RequestContext = requestContext;
return handler;
}
}
public class HotSwapMvcHandler : System.Web.Mvc.MvcHandler
{
protected override Type GetControllerType(string controller)
{
string name = controller + "Controller";
string file = "~/Controllers/" + name + ".cs";
if (!System.IO.File.Exists(HttpContext.Current.Server.MapPath(file)))
return base.GetControllerType(controller);
System.Reflection.Assembly assembly = System.Web.Compilation.BuildManager.GetCompiledAssembly(file);
return assembly.GetType(name, true, true);
}
}
上面2個類, 寫在App_Code裡就OK了, 然後, 需要修改一下 RouteTable 的寫法:
RouteTable.Routes.Add(new Route
{
Url = "[controller]/[action]/[id]",
Defaults = new { action = "Index", id = "" },
RouteHandler = typeof(HotSwapMvcRouteHandler)
});
注意一下 , RouteHandler由MvcRouteHandler替換成 HotSwapMvcRouteHandler 了.
這樣HotSwapMvcRouteHandler的代碼就能夠被執行, 返回HotSwapMvcHandler
HotSwapMvcHandler 這裡得到了一個 controller 的參數, 就是它了.
我們要做的事情,就是根據它 , 找到我們想要的 Controller
上面的GetControllerType的具體實現也實在太簡單了.
如果存在 ~/Controllers/XxxControler.cs
就編譯它, 然後直接返回 XxxController 類型.
否則就按傳統的方式去尋找對應的類.
----
OK , 就這樣2步, 就實現了在 ~/Controllers/ 中存放Controller代碼的目的了.
重溫一下這2步:
1. App_Code中增加 HotSwapMvcRouteHandler , HotSwapMvcHandler
2. Global.asax中修改RouteTable的定義
然後,就可以在 ~/Controllers/ 下增加 TestController.cs , 內容是
public class TestController : Controller
{
[ControllerAction]
public void Index()
{
ViewData["typename"] = this.GetType().AssemblyQualifiedName;
ViewData["version"] = "version5";
RenderView("index");
}
}
然後建立對應的 ~/Views/Test/index.aspx 把東西顯示出來:
index.aspx
<%=ViewData["version"] %>
<%=ViewData["typename"] %>
<%=Application["mystr"] = "1" + Application["mystr"]%>
顯示:
version5
--------------------------------------------------------------------------------
TestController, App_Web_testcontroller.cs.39ee6e8a.c0bebgfm, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
--------------------------------------------------------------------------------
111
不斷地重新整理它, Application["mystr"]就會越來越長.
然後去修改 TestController.cs 把. 把ViewData["version"] = "version123";
那麼就會立刻生效, 顯示version123,而Application["mystr"]沒有重設, 證明ASP.NET並沒有重啟.
想提高開發的方便性的朋友 , 不妨試試上面的代碼.
本文轉自
http://blog.joycode.com/lostinet/archive/2007/12/11/112496.aspx