понедельник, 6 декабря 2010 г.

ASP.NET MVC 3 + Razor

После пары статей об эффективном написании кода в Visual Studio 2010, продолжаю разговор об использовании Razor. Теперь, после выхода ASP.NET MVC 3 Release Candidate, это стало более интересным и близким к реальной жизни. В этой статье речь пойдет о создании приложения на MVC 3 и возможностях Razor для поддержки целостной структуры страниц.

Для тех, кто не читал статью о синтаксисе Razor – крайне рекомендую, хотя и постараюсь здесь не использовать слишком много его “фишек”. Также дальнейшее повествование подразумевает некоторое знакомство с технологией ASP.NET MVC.

Установка ASP.NET MVC 3 RC

Для работы с MVC 3 Release Candidate потребуется, для начала, его установить. Из важных моментов – если установлен Async CTP, отладка работать не будет, сравнительно полный список известных проблем – в Release Notes (забыли, например, упомянуть замену параметра optional на required для RenderSection).

Если есть желание ознакомиться с исходным кодом для этой статьи – есть архив (всего 34KB) на google docs.

Для тех, кто пользуется ReSharper и его Intellisense есть не очень приятная новость. Пока (до выхода ReSharper 6) поддержка Intellisense в Razor ограничена (работает, когда в явном виде используешь Ctrl+Space, иногда требуется набрать первую букву). Тем, кого это сильно расстраивает, можно посоветовать переключиться в настройках ReSharper на Visual Studio Intellisense (Ctrl+Alt+Space будет по-прежнему вызывать ReSharper Intellisense).

Создание нового проекта
Для создания проекта необходимо в списке проектов выбрать ASP.NET MVC 3 Web Application:

Создание нового проекта MVC

После этого на ваш выбор будет предложено два варианта – создать пустой проект или “Internet Application”. Для тех, кому MVC в новинку, однозначно рекомендую последний вариант (полезно посмотреть на реализацию Account). И, для того, чтобы получить View на основе Razor, имеет смысл оставить этот View Engine (по крайней мере, у меня он был выбран по умолчанию, не уверен на 100% относительно установки на “чистую” студию):

Настройка нового проекта MVC

Для начала, тестовый проект создавать необязательно (тем более, что я сейчас пользуюсь NUnit, который, судя по всему, в этом диалоге не поддерживается).

Создав проект, получим следующую структуру для View:

новый проект в SolutionExplorer

Обратите внимание на новые симпатичные иконки, довольно лаконично отражающие синтаксис Razor :) А если перейти к более серьезным вещам – особый интерес для нас представляют _Layout.cshtml, _ViewStart.cshtml и _LogOnPartial.cshtml. Подробности о них далее.

Если вы пока еще не используете в разработке ASP.NET MVC и создали проект типа “Internet Application”, то можете запустить его по Ctrl+F5 и посмотреть на получившееся элементарное приложение. Кстати, несмотря на его элементарность, подключив к нему базу пользователей вы заодно получите работающую страницы регистрации, логина и смены пароля. И еще один мелкий, но приятный бонус – вполне нормальный для простых приложений CSS.

Layout

Честно говоря, мне сложно использовать вместо “Layout” русскоязычные аналоги (разметка/компоновка/схема/макет) – другие ассоциации, поэтому оставлю как есть.
Как вы знаете, в ASP.NET есть “master page”, который позволяет достаточно удобно организовывать расположение элементов на странице. В случае с Razor это Layout.

Для нашего проекта Layout по умолчанию содержится в файле _Layout.cshtml. Хочу обратить ваше внимание на то, что название этого файла никак не влияет на поведение по умолчанию – он используется для всех View, потому что указан в файле _ViewStart.cshtml, но об этом позже.

Содержимое файла _Layout.cshtml в новом проекте следующее:

пример содержимого _Layout.cshtml

Рассмотрим значимое содержимое этого файла (на тексте и стилях заострять внимание не буду):
  1. “_LogOnPartial” – это подключение Partial View для отображения статуса относительно входа в систему. Ссылается на файл _LogOnPartial.cshtml, выводящий стандартное приветствие или ссылку для входа.
  2. ActionLink – ссылки на методы контроллера HomeController, оформленные с помощью CSS в виде горизонтального меню.
  3. RenderBody – директива, которая “рисует”, собственно, тот View, для которого работает данный Layout.

Использование нескольких Layout

Иногда может потребоваться использование нескольких layout (например, для администрирования и просмотра сайта). В качестве примера изменим отображение страницы about.

Создадим layout для всплывающих окон, добавив файл _PopupLayout.cshtml со следующим содержанием:

пример содержимого PopupLayout.cshtml

Для файла About.cshtml, зададим новый layout – переопределим заданный по умолчанию непосредственно в заголовке нашего View:

About layout

А в основном layout поменяем ссылку на “About”:

модификация ссылки для About

Теперь, запустив приложение и нажав в меню “About” получим всплывающее окно без меню и ссылки для Logon, за счет использования другого layout.

Partial Views и секции

При использовании Razor у нас есть еще две возможности для создания достаточно сложного Layout – Partial Views и секции.

Первое понятие – Partial Views – должно быть хорошо знакомо тем, кто уже использует MVC. Для тех, кто его еще не использует – это некий аналог ascx-файлов. В качестве примера уже упоминался _LogOnPartial.cshtml (подключение описано выше в файле _Layout.cshtml). Его содержимое выглядит настолько просто, насколько это возможно (не выделяя специальные методы):

пример содержимого LogOnPartial


Секции – это, по сути, аналог ContentPlaceHolder. Иными словами, вы описываете вызов RenderSection по названию в файле _Layout.cshtml, а во View описываете секцию. Есть возможность вызвать метод RenderSection с параметром required = false, тогда не будет возникать ошибки при отображении страниц, где эта секция не описана.

Так выглядит отображение секции (в этом примере есть как обязательная, так и необязательная секции):

пример вызова RenderSection

Пример, естественно, надуманный – обычно footer одинаковый для всех страниц. А так выглядит соответствующая обязательная секция в файле Index.cshtml:

пример секции в Razor

Вложенный Layout

Теперь, чтобы показать возможность создавать действительно сложный Layout, приведем пример, когда они (Layout – страницы, аналог master page) вложенные. Допустим, нам захотелось разнести вышеупомянутый  _PopupLayout.cshtml на две структурных части – нет ничего проще.

Так будет выглядеть файл _PopupCommonLayout.cshtml:

пример содержимого _PopupCommonLayout.cshtml

А так будет выглядеть файл _PopupLayout.cshtml:

пример вложенного Layout

Серверные комментарии

Теперь, о более элементарных вещах :)
Наверняка вы знаете, что иногда обычных комментариев на странице недостаточно, и необходимо использовать серверные. Теперь Razor использует, на мой взгляд, максимально простой синтаксис для серверных комментариев – @* *@. Выглядит это так:

Razor - пример серверных комментариев

При этом, внутри кода в Razor можно пользоваться как обычными комментариями:

Razor - пример комментариев внутри блока кода

Так и серверными (обратите внимание на подсветку C# кода для закрывающей скобки):

Razor - пример серверных комментариев внутри блока кода

ViewStart

И, напоследок, о том, что уже упоминал ранее. Чтобы выполнить некоторый код для всех View теперь можно использовать файл _ViewStart.cshtml. По аналогии с web.config, можно поместить разные варианты этого файла в разные подпапки с View. Обычно, он используется для задания Layout:

пример содержимого _ViewStart.cshtml

В случае, если Layout задан и во View, то, разумеется, приоритет у заданного во View. Чаще всего, смешение этих двух подходов не является хорошей идеей, однако для демонстрации подойдет.

Резюме

Razor теперь нормально поддерживается в ASP.NET MVC 3, а его возможности для верстки страниц лично меня весьма радуют. Все это немного омрачается неполноценной поддержкой Razor в ReSharper, надеюсь, это ненадолго…

В целом, базовые возможности движка Razor на этом этапе я описал (если принять во внимание предыдущий пост про синтаксис Razor), если что-то интересное осталось за кадром или есть какие-то вопросы – милости прошу в комментарии.

6 комментариев:

  1. Спасибо! Полезно!

    ОтветитьУдалить
  2. всегда было интересно:
    зачем нужно renderBody ведь можно просто сделать секцию?

    ОтветитьУдалить
  3. >зачем нужно renderBody ведь можно просто сделать секцию?

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

    ОтветитьУдалить
  4. Последнее время двигаемся в сторону лохматых времен (MVC,Razor), когда визуальное представление смешивалось с логикой - код спагетти как в PHP.
    Дизайнеры и верстальщики HTML будут в "восторге" !

    ОтветитьУдалить
  5. To @Анонимный

    Не соглашусь.
    * По сравнению, скажем, с чистым ASP, есть строгая типизация
    * MVC - лохматые времена? Вариант с классическими Web Forms (code-behind + попытка сделать web-разработку аналогичной windows-разработке с помощью костылей) видится мне значительно более плохим.
    Естественно, это мое личное мнение :)
    * IMHO, для сложных систем с хорошей архитектурой код и разметка останутся такими же простыми и понятными.

    ОтветитьУдалить
  6. Спасибо, долго искал про вложеныые layout. Оказалось крайне просто

    ОтветитьУдалить