2014-01-21 36 views
3

我嘗試預編譯Azure WebApplication,因此第一次點擊並不會在頁面的每次首次點擊時花費幾秒鐘時間。Azure預編譯似乎不起作用

我有下面的代碼在我WebRole.Run()

using (var server_manager = new ServerManager()) 
{ 
    var main_site    = server_manager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"]; 
    var main_application  = main_site.Applications["/"]; 
    var main_application_pool = server_manager.ApplicationPools[main_application.ApplicationPoolName]; 

    string physical_path = main_application.VirtualDirectories["/"].PhysicalPath; 

    main_application["preloadEnabled"] = true; 
    main_application_pool["autoStart"] = true; 
    main_application_pool["startMode"] = "AlwaysRunning"; 

    server_manager.CommitChanges(); 

    Log.Info("Building Razor Pages", "WebRole"); 

    var build_manager = new ClientBuildManager("/", physical_path); 
    build_manager.PrecompileApplication(); 

    Log.Info("Building Razor Pages: Done", "WebRole"); 
} 

它似乎並沒有拋出任何異常,當我看着日誌大約需要55秒做build_manager.PrecompileApplication()

似乎對我很正確。

除了當我第一次嘗試加載頁面時仍會受到打擊。如果我看看MiniProfiler,我特別看到Find部分需要很長時間。我仍然懷疑這是彙編,因爲1.5秒找到一個文件似乎對我來說有點長。

enter image description here

有什麼毛病我上面的方法呢?有沒有辦法檢查頁面是否真的編譯?而且,在編譯的情況下,還能有什麼?爲什麼o爲什麼東西太複雜了......

+0

你能試着從這個問題http://stackoverflow.com/q/10830044/57428的代碼,看看它是否有差別? – sharptooth

+0

假設VirtualPath是「/」,問題中的代碼似乎是相同的。或者你的意思是添加第三個'null'參數或額外的ClientBuildManagerParameters? –

+0

不,我的意思是枚舉應用程序的所有'VirtualDirectories'並使用它們的路徑。與直接傳遞'/'相比,可能會有一些愚蠢的細微差別。 – sharptooth

回答

2

我從來沒有得到過它的工作。可能有些奇怪的Web.config/Azure /項目設置似乎關閉了,但我從未找到它。

在您進一步閱讀之前,我建議您先爲您的項目嘗試這種方法:https://stackoverflow.com/a/15902360/647845。 (因爲它不依賴於黑客)

我的解決方法是相對簡單的,我搜索應用程序中的所有刀片意見,而且比我只是嘗試用嘲笑ControllerContext來呈現他們,駁回的結果。由於一個非有效的ViewModel,所有的Views都會拋出一個異常,但只要視圖首先被編譯,這並不重要。

private void PrecompileViews() 
{ 
    string search_path = GetSearchPath(); 

    // Create a dummy ControllerContext - using the HomeController, but could be any controller 
    var http_context = new HttpContext(new HttpRequest("", "http://dummy", ""), new HttpResponse(new StringWriter())); 
    http_context.Request.RequestContext.RouteData.Values.Add("controller", "Home"); 
    var controller_context = new ControllerContext(new HttpContextWrapper(http_context), http_context.Request.RequestContext.RouteData, new HomeController()); 

    // loop through all views, and try to render them with the dummy ControllerContext 
    foreach (var file in Directory.GetFiles(search_path, "*.cshtml", SearchOption.AllDirectories)) 
    { 
     string relative_view_path = "~" + file.Replace(search_path, "", StringComparison.InvariantCultureIgnoreCase); 

     var view_result = new ViewResult { ViewName = relative_view_path }; 

     try 
     { 
      view_result.ExecuteResult(controller_context); 
     } 
     catch (Exception) 
     { 
      // Almost all views will throw exceptions, because of a non valid ViewModel, 
      // but that doesn't matter because the view stills got compiled 
     } 
    } 
} 

GetSearchPath返回你的應用程序的根目錄:

private string GetSearchPath() 
{ 
    string bin_path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase); 
    string local_path = new Uri(bin_path).LocalPath; 
    return Path.GetFullPath(Path.Combine(local_path, "..")); 
} 

我呼籲這一切在我的Global.asax結束:

protected void Application_Start() 
{ 
    [...] 
    PrecompileViews(); 
} 
+0

Application_Start()會在每次應用程序池回收時每運行27小時或什麼東西以及類似20分鐘不活動之後運行。 – sharptooth

+0

我禁用了超時(請參閱:http://blog.smarx.com/posts/controlling-application-pool-idle-timeouts-in-windows-azure)。應用程序池回收我必須看看,謝謝! –

+0

有一個更好的方法來運行這個代碼 - 製作一個控制器 - 動作對,並通過從角色OnStart()內部向自己發送一個HTTP請求來調用它。檢查操作中的「HttpRequest.IsLocal」,以便外部人員不能觸發它。 – sharptooth