2011-10-03 16 views
8

Recentemente ho iniziato a giocare con la capacità di IIS di applicare una fase di riscaldamento alla mia applicazione web attraverso l'uso dell'interfaccia IProcessHostPreloadClient (vedi here per la guida su come impostare questo su). Questo ha funzionato alla perfezione, o almeno lo pensavo, perché una delle cose "intelligenti" che ho fatto è stata quella di provare e precaricare le mie opinioni ripetendo i miei controller e rendendoli.Precarica visualizzazioni ASP.NET MVC in fase di riscaldamento IIS

Dopo un po 'di tentativi ed errori, ho avuto modo di funzionare e tutto andava bene. Cioè, fino a quando ho notato che tutte le convalide del mio sistema non funzionavano più, né la convalida del client né del server. Suppongo che la convalida sia normalmente collegata alle viste quando MVC recupera una vista per la prima volta e non sono riuscito a farlo. Qualcuno ha un'idea di come questo potrebbe essere incluso nella mia soluzione o forse fatto in un altro modo?

Il codice:

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 { } 
     } 
    } 
} 

risposta

3

Il problema non è con il codice nella domanda ma il momento in cui viene eseguito. Lo spostamento del codice in un'azione mi consente di eseguire la fase di riscaldamento senza problemi. Nel mio caso, suppongo che avrò appena il processo di installazione per chiamare l'azione di riscaldamento dopo che il sistema è stato configurato.

3

risposta non diretta alla sua domanda, ma penso che si dovrebbe dare un'occhiata a Precompiling MVC Razor views using RazorGenerator da David Ebbo

Una ragione per fare questo è di evitare qualsiasi colpo di runtime all'avvio del sito , poiché non è rimasto nulla da compilare in fase di runtime. Questo può essere significativo in siti con molte visualizzazioni.

+0

Uso alcuni metodi di helper Razor globali e non riesco a far funzionare il generatore Razor. Altrimenti, sembra essere uno strumento molto utile. –

+1

Non sono sicuro che le visualizzazioni di precompilazione valgano lo sforzo. Penso che la nuova inizializzazione dell'applicazione IIS con il suo supporto per il riciclo dei processi di sovrapposizione risolva meglio il problema. –

3

C'è un nuovo modulo di Microsoft che fa parte di IIS 8.0 che sostituisce il precedente modulo di riscaldamento. Questo Application Initialization Module for IIS 7.5 è disponibile in un download separato.

Il modulo creerà una fase di riscaldamento in cui è possibile specificare un numero di richieste da completare prima che il server inizi ad accettare le richieste. Queste richieste eseguiranno e compileranno tutte le visualizzazioni in modo più efficace rispetto a quello che stai cercando di ottenere.

Ho risposto a una domanda simile con ulteriori dettagli allo How to warm up an ASP.NET MVC application on IIS 7.5?.

Problemi correlati