Лично меня давно интересовал вопрос — почему разработчики ASP.NET MVC уделяют так много времени на реализицию второстепенных (ИМХО) фич (типа View/Editor Templates и тп), а не решают более острые проблемы? Самые острые проблемы, на мой взгляд — это пережитки WebForms. Возьмите, например, кеширование, которое работает совсем-совсем плохо, потому что предназначено для классического ASP.NET, а не для MVC. Ну и апофеоз архаизма — это, конечно же, WebFormViewEngine.
И вот, 2-го июля 2010 года стало известно — команда ASP.NET MVC наконец-то взялась за разработку нового движка отображения (ViewEngine) — Razor. Чтобы понять истинное значение этой новости нужно, для начала, изучить недостатки и проблемы WebFormViewEngine.
Недостатки и проблемы WebFormViewEngine
1 Несоответствие парадигм
Класс WebFormViewEngine
в пространстве имен System.Web.Mvc
— это, по сути, попытка адаптировать инфраструктуру WebForms для работы в концепции MVC. (Кто-то метко заметил, это тоже самое что "адаптировать каток для колки арехов"). Но известно, что WebForms и MVC используют совершенно разные парадигмы. MVC — это запросо-ориентированный фреймворк, а WebForms — компонентно-ориентированный. Отсюда и возникают проблемы:
- Разный жизненный цикл страниц.
- Для MVC не требуется множество доступных директив.
- Code Behind — зло для MVC.
2 Антиавтономность
От движка отображения требуется одно — генерация текста по шаблону. Естественно, эта задача актуальна не только для веб-приложений и не только для рендеринга видов. Такие генераторы (их еще называют templating engine, один из ярких представителей — velocity) применяются для генерации отчетов, электронных писем и во многих других случаях. Однако, WebFormViewEngine — это больше чем templating engine. Это целая экосистема, поэтому её не получится использовать вне ASP.NET приложения.
3 Нетестируемость
Не секрет, что про существование TDD в Microsoft узнали недавно, а ASP.NET появился давно. Также не секрет, фреймворк WebForms под завязку набит синглтонами и привязан к веб-контексту. Эти тонкие обстоятельства вызывают сложности тестирования любого рода производных от WebForms (вспомним обертки HttpContextBase
и т.п. в MVC). Ну а уж если кому-то захочется заняться такой экзотической вещью как тестирование output\а
WebFormViewEngine`, то из этого вряд ли получится что-нибудь хорошее.
4 Ущербная модель повторного использования разметки
Дублироване кода в шаблонах вида — такая же проблема как дублирование логики в контроллерах или любом другом месте программы. И с этим дублированием нужно бороться. WebFormViewEngine
предлагает нам для этого классическую модель Master Page и эмвецешный RenderPartial
. Этих механизмов явно недостаточно, для некоторых задач приходится придумывать совсем не прямые решения. Достаточно беглого взгляда на модель, которую предлагает, например, Spark, чтобы понять, что она более продвинутая. С partial-разметкой у Spark дела тоже лучше.
5 Многословный синтаксис
В WebFroms хорошим тоном было помещать логику отображения (а иногда и логику предметной области, что греха таить) в code-behind-файл (вспомним гигантские методы Page_Load
). Скриптлеты (<% много_кода %>
) были хоть и существенным, но всё-таки дополнением к этому механизму. В MVC же наоборот, скриптлеты — единственно верный способ описания логики шаблона вида. Так второстепенный механизм вышел на первостепенные роли — кода во вьюшках MVC бывает очень много. И некоторым стало казаться, что два-три символа (<%
, <%=
) — это слишком много.
Еще острее стоит проблема форматирования — масса HTML- и C#-кода в одном файле превращается в кровавое месиво, если нажать Ctrl+K+D.
Сторонние решения
Сообществу давно известны проблемы WebFormViewEngine. Поэтому сторонних движков очень много. Но основной их недостаток — нет глубокой интеграции с Visual Studio. Это проявляется в отсутствии автодополнения, а иногда и подсветки синтаксиса. ReSharper тоже не очень любит сторонние движки. Да и выбор типового .NET разработчика обычно основан на такой логике (пруфлинк, абзац 3-4):
Продукт от Microsof будет жить и поддерживаться также долго, как и сам .NET Framework. А сторонние решения могут завтра перестать существовать.
Razor → луч света в тёмном царстве
И вот появляется новость о скором релизе Razor — движке, который впитал в себя всё лучшее от Spark и NHaml. От описания прелестей хочется какать кирпичами — настолько всё хорошо. (Кому нужны кирпичи — срочно прочитайте на хабре перевод Скота Гатри: Razor — новый движок представлений в ASP.NET). Итак, нам обещают:
- движок, который легко можно использовать вне ASP.NET-проекта;
- открытый исходный код;
- модель Master Layout в духе Spark;
- легкая тестируемость;
- улучшена модель хелперов;
- «облегчённый» синтаксис.
Я специально отметил синтаксис последним пунктом, потому что многие обсуждают и комментируют именно синтаксис. На мой взгляд это второстепенная вещь, по сравнению с остальными изменениями.
Отдельно хочется сказать про хелперы. Сама концепция методов-расширений для генерации элементов разметки хорошо прижилась в MVC. Но выявились и проблемы. В хелпере сложно генерировать большой кусок разметки, потому что оперировать строками html тегов в C#-коде неудобно. Во всяком случае не так удобно, как в предназначенных специально для html файлах aspx/ascx. С другой стороны, механизм Partial View не позволяет передать в дочерний вид множество параметров также легко как в метод расширения. Поэтому приходится искать баланс между двумя этими подходами (RenderPartial
vs Extension method helper
). Razor производит революцию в этом направлении — теперь хелперы можно будет определять не в cs-файлах, а в файлах шаблоннов. То есть мы получаем удобство, безопасность передачи параметров в хелпер и легкость написания разметки. В дополнение к этому появляется возможность передачи мини-шаблона в качестве параметра хелпер-метода. Это тоже должно быть интересно.
В связи со всем сказанным, если Razor действительно так хорош, то после его релиза вообще не вижу смысла дальнейшего использования WebFormViewEngine
. Пусть MVC идёт своей дорогой, Web Forms — своей. Учитывая отношение большинства сообщества к сторонним решениям можно предположить, что вместе с WebFormViewEngine
уйдут в прошлое и источники вдохновения Razor — Spark и NHaml.
"В WebFroms хорошим тоном было помещать логику отображения в code-behinde-файл"
Было таким же плохим тоном, как и любой другой г-но код. Другое дело, что WebForms провоцируют к этому неокрепший ум новичка.
Я имел в виду не логику предметной области, и именно логику отображения. То есть генерацию списков/таблиц, заполнение лейблов и т.п. Это всё обычно располагается в code-behind (
PageLoad
и т.п.) и это нормально. Другое дело, когда в том жеPageLoad
появляется сервисная логика, которая по всем законам должна быть инкапсулирована в отдельном классе. И здесь я с вами абсолютно согласен — это провоцирует новичков писать г-но-код.