2011-10-03 10 views
8

Recientemente comencé a jugar con la capacidad de IIS para aplicar un paso de calentamiento a mi aplicación web mediante el uso de la interfaz IProcessHostPreloadClient (busque here para obtener orientación sobre cómo configurar esto arriba). Esto funcionó muy bien, o al menos pensé que sí, porque una de las cosas 'inteligentes' que hice fue intentar precargar mis puntos de vista al iterar sobre mis controladores y representarlos.Precargar vistas ASP.NET MVC en el paso de calentamiento IIS

Después de un poco de prueba y error, lo hice funcionar y todo estaba bien. Es decir, hasta que noté que ya no funcionaba toda la validación para mi sistema, ni la validación del cliente ni la del servidor. Supongo que la validación normalmente está conectada a las vistas cuando MVC recupera una vista por primera vez y no lo hice. ¿Alguien tiene una idea de cómo esto podría incluirse en mi solución o quizás de otra manera?

El código:

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

Respuesta

3

El problema no está en el código de la pregunta, sino en el momento en que se ejecuta. Mover el código a una acción me permite realizar el paso de calentamiento sin problemas. En mi caso, supongo que obtendré el proceso de instalación para llamar a la acción de calentamiento una vez que se haya configurado el sistema.

3

respuesta no directa a su pregunta, pero creo que deberías echar un vistazo a Precompiling MVC Razor views using RazorGenerator por David Ebbo

Una razón para hacer esto es para evitar cualquier tiempo de ejecución golpeado cuando se inicia su sitio , ya que no queda nada por compilar en tiempo de ejecución. Esto puede ser significativo en sitios con muchas vistas.

+0

Utilizo algunos métodos globales Razor helper y no consigo que el generador Razor funcione con ellos. De lo contrario, parece ser una herramienta muy útil. –

+1

No estoy seguro de que valga la pena precompilar las vistas. Creo que la nueva inicialización de la aplicación IIS con su soporte para el reciclaje de procesos superpuestos resuelve mejor el problema. –

3

Hay un nuevo módulo de Microsoft que es parte de IIS 8.0 que reemplaza el módulo de precalentamiento anterior. Este Application Initialization Module for IIS 7.5 está disponible por separado.

El módulo creará una fase de calentamiento donde puede especificar una serie de solicitudes que deben completarse antes de que el servidor empiece a aceptar solicitudes. Estas solicitudes se ejecutarán y compilarán todas sus vistas de una manera más sólida que lo que está tratando de lograr.

He respondido una pregunta similar con más detalles en How to warm up an ASP.NET MVC application on IIS 7.5?.

Cuestiones relacionadas