Предварительная загрузка ASP.NET MVC в шаге разогрева IIS - PullRequest
8 голосов
/ 03 октября 2011

Я недавно начал играть со способностью IIS применять шаг прогрева к моему веб-приложению с помощью интерфейса IProcessHostPreloadClient (см. здесь , чтобы узнать, как это настроить) , Это сработало замечательно, или, по крайней мере, я так думал, потому что одна из «умных» вещей, которые я сделал, - попытаться предварительно загрузить свои представления, перебирая контроллеры и отображая их.

После небольшого количества проб и ошибок я заставил его работать, и все было хорошо. То есть, пока я не заметил, что вся проверка для моей системы больше не работала, ни проверка клиента, ни проверка сервера. Я предполагаю, что проверка обычно подключается к представлениям, когда 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 голосов
/ 09 ноября 2011

Проблема не в коде, о котором идет речь, а в том, в какое время он выполняется.Перемещение кода в действие позволяет мне без проблем выполнить шаг прогрева.В моем случае, я думаю, я получу процесс установки для вызова действия разогрева после того, как система будет настроена.

3 голосов
/ 03 октября 2012

Существует новый модуль от Microsoft, который является частью IIS 8.0 и заменяет предыдущий модуль прогрева.Этот Модуль инициализации приложения для IIS 7.5 доступен для отдельной загрузки.

Модуль создаст фазу прогрева, где вы можете указать количество запросов, которые должны быть выполнены, прежде чем сервер начнет принимать запросы.Эти запросы будут выполнять и компилировать все ваши представления более надежным способом, чем вы пытаетесь достичь.

Я ответил на аналогичный вопрос с более подробной информацией на Как прогреть ASP.NET MVCприложение на IIS 7.5? .

3 голосов
/ 03 октября 2011

Не прямой ответ на ваш вопрос , но я думаю, вам стоит взглянуть на Прекомпиляция видов MVC Razor с помощью RazorGenerator от David Ebbo

Одна из причин сделать это, чтобы избежать попадания во время выполнения, когда ваш сайт запускается, так как во время выполнения не осталось ничего для компиляции. Это может быть значимо на сайтах с большим количеством просмотров.

...