2011-10-03 66 views
8

我最近開始使用IIS的能力,通過使用IProcessHostPreloadClient接口向我的Web應用程序應用預熱步驟步驟(請參閱here以獲取有關如何設置此步驟的指導向上)。這個結果很好,或者至少我認爲它確實如此,因爲我做的「聰明」事情之一就是通過迭代我的控制器並渲染它們來嘗試並預裝我的視圖。在IIS預熱步驟中預加載ASP.NET MVC視圖

經過一些試驗和錯誤,我得到它的工作,一切都很好。也就是說,直到我發現我的系統的所有驗證不再有效,無論是客戶端還是服務器驗證。我假設驗證通常是在MVC第一次檢索視圖時連接到視圖,但我沒有這樣做。有沒有人有一個想法如何將這可能包含在我的解決方案或可能以另一種方式?

代碼:

public class Warmup : IProcessHostPreloadClient 
{ 
    public void Preload(string[] parameters) 
    { 
     //Pre-render all views 
     AutoPrimeViewCache("QASW.Web.Mvc.Controllers", @"Views\"); 
     AutoPrimeViewCache("QASW.Web.Mvc.Areas.Api.Controllers", @"Areas\Api\Views\", "Api"); 
    } 

    private void AutoPrimeViewCache(string controllerNamespace, string relativeViewPath, string area = null) 
    { 
     var controllerTypes = typeof(Warmup).Assembly.GetTypes().Where(t => t.Namespace == controllerNamespace && (t == typeof(Controller) || t.IsSubclassOf(typeof(Controller)))); 
     var controllers = controllerTypes.Select(t => new { Instance = (Controller)Activator.CreateInstance(t), Name = t.Name.Remove("Controller") }); 

     foreach (var controller in controllers) 
     { 
      var viewPath = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, relativeViewPath + controller.Name); 
      var viewDir = new DirectoryInfo(viewPath); 
      if (viewDir.Exists) 
      { 
       var viewNames = viewDir.EnumerateFiles("*.cshtml").Select(f => f.Name.Remove(".cshtml")).ToArray(); 
       PreloadController(controller.Instance, area, viewNames); 
      } 
     } 
    } 

    private void PreloadController(Controller controller, string area, params string[] views) 
    { 
     var viewEngine = new RazorViewEngine(); 

     var controllerName = controller.GetType().Name.Remove("Controller"); 
     var http = new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://a.b.com", null), new HttpResponse(TextWriter.Null))); 
     var routeDescription = area == null ? "{controller}/{action}/{id}" : area + "/{controller}/{action}/{id}"; 
     var route = new RouteCollection().MapRoute(
      "Default", // Route name 
      routeDescription, // URL with parameters 
      new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
     ); 

     var routeData = new RouteData(route, route.RouteHandler); 
     routeData.Values.Add("controller", controllerName); 
     if (area != null) 
     { 
      routeData.Values.Add("area", area); 
      routeData.DataTokens.Add("area", area); 
     } 
     routeData.DataTokens.Add("controller", controllerName); 
     routeData.Values.Add("id", 1); 
     routeData.DataTokens.Add("id", 1); 
     var controllerContext = new ControllerContext(http, routeData, controller); 
     var vDic = new ViewDataDictionary(); 
     var vTemp = new TempDataDictionary(); 

     foreach (var view in views) 
     { 
      var viewResult = viewEngine.FindView(controllerContext, view, null, false); 
      if (viewResult.View == null) 
       throw new ArgumentException("View not found: {0} (Controller: {1})".Args(view, controllerName)); 
      var viewContext = new ViewContext(controllerContext, viewResult.View, vDic, vTemp, TextWriter.Null); 
      try { viewResult.View.Render(viewContext, TextWriter.Null); } 
      catch { } 
     } 
    } 
} 

回答

3

問題不在於問題中的代碼,而在於它執行的時間。將代碼移動到一個動作中,可以讓我執行熱身步驟而不會出現任何問題。就我而言,我想我會在系統配置好之後讓安裝過程調用熱身操作。

3

不直接回答你的問題,但我認爲你應該看看Precompiling MVC Razor views using RazorGenerator由大衛博

一個理由這樣做是爲了避免當您的站點 開始時,任何運行時命中,因爲在運行時沒有什麼需要編譯的。這可以是 在有很多視圖的網站中很重要。

+0

我使用了一些全局Razor幫助器方法,我無法使Razor生成器與它們一起工作。否則,它看起來是一個非常有用的工具。 –

+1

我不確定預編譯視圖是否值得付出。我認爲新的IIS應用程序初始化支持重疊流程回收,可以更好地解決問題。 –

3

有一個來自Microsoft的新模塊,它是IIS 8.0的一部分,它取代了之前的預熱模塊。這Application Initialization Module for IIS 7.5可單獨下載。

該模塊將創建一個熱身階段,您可以在服務器開始接受請求之前指定一些必須完成的請求。這些請求將以比您想要實現的更強大的方式執行和編譯所有視圖。

我已在How to warm up an ASP.NET MVC application on IIS 7.5?回答了一個類似的問題,更多詳細信息。