Долгое время одним из первых шагов после создания нового MVC-сайта у меня было редактирование .csproj и добавление магического элемента
<MvcBuildViews>true</MvcBuildViews>
Напомню, что этой директивой включается компиляция Razor-вьюшек, таким образом об ошибках в .cshtml файлах можно узнать не в рантайме (при открытии веб-странички), а во время компиляции проекта. Опция, безусловно, очень удобная, но очень сильно замедляющая процесс сборки. Так, при отключенной опции наш средних размеров MVC-проект собирается за 1 секунду, а со включенной — за 10 секунд (в проекте всего лишь чуть больше 100 cshtml файлов).
Такая немаленькая задержка очень серьезно сказывается на разработке — по сути при каждом билде можно легко успеть «переключиться» на браузер и пролистать пару страничек :)
Таким образом от MvcBuildViews очень захотелось отказаться, но при этом не потерять возможность обнаружения ошибок во вьюшках во время компиляции.
Проблему решил замечательный RazorGenerator от Дэвида Эббо. РазорГенератор интегрируется в качестве Custom Tool для Visual Studio и преобразует каждую вьюшку в соответствующий c#-код, который и компилируется в момент компиляции проекта и выдает ошибки абсолютно аналогичные MvcBuildViews. При этом время компиляции с RazorGenerator’ом составляет(в нашем случае) ту же 1 секунду, что и без него (с отключенным MvcBuildView). Итоговый выигрыш — в 10 раз (10 сек — компиляция + MvcBuildViews, 1 сек — компиляция + RazorGenerator).
Внедрение RazorGenerator’а очень просто и подробно расписано на странице проекта:
- Устанавливаем расширение «Razor Generator» для Visual Studio (Tools->Extension Manager->Online Gallery, набрать «Razor Generator» в поиске и установить)
- Устанавливаем NuGet-пакет RazorGenerator.MVC — он добавит собственный ViewEngine, который будет обрабатывать скомпилированные вьюшки
- Для обработки всех существующих вьюшек в Nuget-консоли вводим «Enable-RazorGenerator» (либо вручную для каждой вьюшки вписываем в поле Custom Tool — «RazorGenerator»
- Компилируем проект и радумеся в разы ускорившемуся процессу сборки
С какими проблемами я столкнулся при внедрении RazorGenerator:
- Если у вас есть какие-то Razor-хэлперы в App_Code — то у них для сгенерированных c# файлов будет стоять Build Action — Content. Естественно, они при этом не будут компилироваться. Необходимо вручную поменять Build Action на Compile
- Еще про хэлперы в App_Code — для их использования необходимо будет добавить @using YourProjectNamespace.App_Code в каждую вьюшку, где они используются (ну или добавить неймспейс один раз в VIEWS/web.config system.web.webPages.razor/pages/namespaces плюс аналогично в Areas/web.config, если такая папка у вас есть)
- Почему-то RazorGenerator-у не нравилось использование статических методов от String с заглавной буквы (например, String.IsNullOrEmpty). Впрочем, изменение буквы с заглавной на строчную решило проблему (String.Empty стал string.Empty и все заработало)
- Одинаковые имена у вью-моделей и вьюшек. У меня был один случай, когда вью-модель называлась StageView и вьюшка для него называлась StageView.cshtml. Во вьюшке первыми же строками шло:
@using IndexingImage.Mvc.HomeController @model StageView
Сгенеренный РазорГенератором код выглядел при этом так:
public class StageView : System.Web.Mvc.WebViewPage<StageView>
Нетрудно догадаться, что дженериковым параметром для вьюшки стала сама эта вьюшка, а далеко не вью-модельный класс StageView. Проблема решилась просто — прописыванием полного имени класса в директиве @model
@model IndexingImage.Mvc.HomeController.StageView
К слову, у RazorGenerator’a есть и еще один полезный сайд-эффект: поскольку компиляция вьюшек происходит одновременно с компиляцией проекта, то при запуске проекта отсутствует задержка при первом открытии веб-страниц (в норме именно в этот момент обычно происходит компиляция .cshtml файлов).
Удачи с использованием RazorGenerator’a!
Остались вопросы — добро пожаловать в комментарии.
P.S. Из минусов — расширение Razor Generator должны будут поставить себе все разработчики.
У меня вообще директива @model Blabla сгенерировалась как Write(model). WTF?