I recently started playing with the ability of IIS to apply the warm-up step step to my web application using the IProcessHostPreloadClient interface (see here for information on how to install this). It worked out great, or at least I thought it happened because one of the smart things I did was try to preload my views, iterate over my controllers and render them.
After some trial and error, I got it to work, and everything was fine. That is, until I noticed that all the checks for my system no longer work, neither the client check, nor the server. I assume that validation usually connects to the views when MVC first gets the view, and I could not do it. Does anyone have an idea how this could be included in my solution or perhaps done differently?
The code:
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://abcom", 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 { } } } }