Работа с Razor в представлении
100ASP.NET --- ASP.NET MVC 5 --- Работа с Razor в представлении
В предыдущей статье мы имели возможность создать специальный механизм визуализации, реализовав только два интерфейса. Следует признать, что в конечном итоге мы получили простое подобие механизма, который генерировал довольно неуклюжие представления, но зато вы увидели, что концепция расширяемости MVC поддерживается на протяжении всего конвейера обработки запросов.
Сложность в механизм визуализации привносится системой шаблонов представлений, которая включает фрагменты кода, поддерживает компоновки и скомпилирована для оптимизации производительности. Мы не делали ничего подобного в своем простом механизме визуализации, и по большому счету не должны это делать, потому что обо всем позаботится механизм Razor.
В Razor доступна функциональность, которую требуют практически все приложения MVC. Необходимость в создании специального механизма визуализации возникает лишь в очень малом числе проектов. Основы синтаксиса Razor были даны статьях Модели и компоновки в Razor и Выражения Razor. В этой и следующих статьях будет показано, как применять другие средства для создания и визуализации представлений Razor. Вы также узнаете, каким образом настраивать механизм Razor.
Пример приложения
Мы создали новый проект MVC по имени WorkingWithRazor с использованием шаблона Empty (Пустой) и отметкой флажка MVC в разделе Add folders and core references for (Добавить папки и основные ссылки для). В проект добавлен контроллер Home, код которого показан в примере:
using System;
using System.Web.Mvc;
namespace WorkingWithRazor.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
string[] names = { "Яблоко", "Апельсин", "Груша" };
return View(names);
}
}
}
Кроме того, в папке /Views/Home создано представление по имени Index.cshtml. Содержимое этого файла представления приведено ниже:
@model string[]
@{
ViewBag.Title = "Index";
}
<h2>Названия фруктов</h2>
@foreach (string fruit in Model)
{
<br /><span><b>@fruit</b></span>
}
Визуализация представлений Razor
Для улучшения показателей производительности механизм визуализации Razor компилирует представления, созданные в приложении. Представления транслируются в классы C#, после чего компилируются; именно поэтому настолько легко включать фрагменты кода C#. Полезно просмотреть исходный код, сгенерированный для представлений Razor, поскольку это позволит лучше понять многие средства Razor.
Представления в приложении MVC не компилируются вплоть до момента запуска приложения, так что для просмотра классов, созданных Razor, понадобится запустить приложение и перейти к действию /Home/Index. Начальный запрос к приложению MVC инициирует процесс компиляции для всех представлений. Вывод произведенного запроса показан на рисунке ниже:
По соглашению классы, сгенерированные из файлов представлений, сначала сохраняются на диске в виде файлов кода C# и затем компилируются, а это значит что можно просмотреть операторы C#, относящиеся к представлению. Сгенерированные файлы расположены в папке:
C:\Users\Имя пользователя\AppData\Local\Temp\Temporary ASP.NET Files
в системах Windows 7 и Windows 8.
Нахождение файла кода, сгенерированного для конкретного представления, требует определенного внимания. Обычно имеется множество папок с загадочными именами, к тому же имена файлов .cs не соответствуют именам содержащихся в них классов. К примеру, класс, сгенерированный для представления из примера выше, был обнаружен в файле по имени "App_Web_o0mtztby.0.cs" внутри папки "root\321dfcd8\64cbe7dd\". В примере ниже приведен слегка упорядоченный код этого класса:
namespace ASP {
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Helpers;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using WorkingWithRazor;
public class _Page_Views_Home_Index_cshtml : System.Web.Mvc.WebViewPage<string[]> {
public _Page_Views_Home_Index_cshtml() {
}
protected ASP.global_asax ApplicationInstance {
get {
return ((ASP.global_asax)(Context.ApplicationInstance));
}
}
public override void Execute() {
ViewBag.Title = "Index";
BeginContext("~/Views/Home/Index.cshtml", 52, 31, true);
WriteLiteral("\r\n\r\n<h2>Названия фруктов</h2>\r\n");
EndContext("~/Views/Home/Index.cshtml", 52, 31, true);
foreach (string fruit in Model)
{
BeginContext("~/Views/Home/Index.cshtml", 120, 10, true);
WriteLiteral(" <br />");
EndContext("~/Views/Home/Index.cshtml", 120, 10, true);
BeginContext("~/Views/Home/Index.cshtml", 130, 9, true);
WriteLiteral("<span><b>");
EndContext("~/Views/Home/Index.cshtml", 130, 9, true);
BeginContext("~/Views/Home/Index.cshtml", 145, 13, true);
WriteLiteral("</b></span>\r\n");
EndContext("~/Views/Home/Index.cshtml", 145, 13, true);
}
}
}
}
Первым делом обратите внимание, что класс является производным от WebViewPage<T>, где T - это тип модели (WebViewPage<string[]> в рассматриваемом примере). Подобным образом поддерживаются строго типизированные представления. Кроме того, взгляните на имя сгенерированного класса - _Page_Views_Home_Index_cshtml. Как видите, в имени класса закодирован путь к файлу представления. Таким способом Razor отображает запросы к представлениям на экземпляры скомпилированных классов.
В методе Execute() производится обработка операторов и элементов представления. Фрагменты кода, предваренные символом выражаются непосредственно как операторы C#. Элементы HTML обрабатываются с помощью метода WriteLiteral(), который записывает содержимое параметра в результат в том виде, как он задан. Это отличается от метода Write(), который используется для переменных C# и кодирует строковые значения для безопасного применения на HTML-странице.
Методы Write() и WriteLiteral() записывают содержимое в объект TextWriter. Это тот же самый объект, который передается методу IView.Render(), как было показано в предыдущей статье. Цель скомпилированного представления Razor заключается в генерации статического и динамического содержимого и отправка его клиенту через TextWriter. Об этом полезно помнить, когда будут рассматриваться вспомогательные методы HTML.
Конфигурирование местоположений для поиска представлений
При поиске представления механизм визуализации Razor следует стандартному соглашению. Например, в случае запроса представления Index, ассоциированного с контроллером Home, механизм Razor просматривает следующий список представлений:
~/Views/Home/Index.cshtml ~/Views/Home/Index.vbhtml ~/Views/Shared/Index.cshtml ~/Views/Shared/Index.vbhtml
Как вам уже известно, Razor в действительности не ищет файлы представлений на диске, поскольку они уже скомпилированы в классы C#. Механизм Razor ищет скомпилированные классы, соответствующие этим представлениям. Файлы .cshtml - это шаблоны, содержащие операторы C#, а файлы .vbhtml содержат операторы Visual Basic.
Чтобы изменить файлы представлений, которые ищет Razor, можно создать подкласс класса RazorViewEngine. Указанный класс является реализацией интерфейса IViewEngine в Razor. Он построен на серии базовых классов, которые определяют набор свойств, указывающих на то, какие файлы представлений будут искаться. Эти свойства описаны в таблице ниже:
Свойство | Описание | Стандартное значение |
---|---|---|
ViewLocationFormats MasterLocationFormats PartialViewLocationFormats |
Местоположения для поиска представлений, частичных представлений и компоновок |
~/Views/{1}/{0}.cshtml ~/Views/{1}/{0}.vbhtml ~/Views/Shared/{0}.cshtml ~/Views/Shared/{0}.vbhtml |
AreaViewLocationFormats AreaMasterLocationFormats AreaPartialViewLocationFormats |
Местоположения для поиска представлений, частичных представлений и компоновок для области данных |
~/Areas/{2}/Views/{1}/{0}.cshtml ~/Areas/{2}/Views/{1}/{0}.vbhtml ~/Areas/{2}/Views/Shared/{0}.cshtml ~/Areas/{2}/Views/Shared/{0}.vbhtml |
Приведенные свойства предшествовали появлению Razor, потому каждый набор из трех свойств имеет те же самые значения. Каждое свойство является массивом строк, которые выражены с использованием формата составных строк.
Ниже перечислены значения параметров, соответствующие заполнителям:
{0} представляет имя представления;
{1} представляет имя контроллера;
{2} представляет имя области.
Для изменения просматриваемых местоположений вы создаете новый класс, производный от RazorViewEngine, и устанавливаете желаемым образом значения одного или нескольких свойств из таблицы.
В целях демонстрации изменения местоположений для поиска в проект добавлена папка Infrastructure, а в ней создан файл класса по имени CustomLocationViewEngine.cs, содержимое которого показано в примере ниже:
using System.Web.Mvc;
namespace WorkingWithRazor.Infrastructure
{
public class CustomLocationViewEngine : RazorViewEngine
{
public CustomLocationViewEngine()
{
ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml",
"~/Views/Common/{0}.cshtml" };
}
}
}
Для свойства ViewLocationFormats указано новое значение. Новый массив содержит элементы только для файлов .cshtml. Вдобавок местоположение, в котором ищутся разделяемые представления, изменено на Views/Common вместо Views/Shared. Производный механизм визуализации регистрируется с использованием коллекции ViewEngines.Engines в методе Application_Start() внутри файла Global.asax, как показано в примере ниже:
using System.Web.Mvc;
using System.Web.Routing;
using WorkingWithRazor.Infrastructure;
namespace WorkingWithRazor
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomLocationViewEngine());
}
}
}
Вспомните, что активатор действий обращается к каждому механизму визуализации, чтобы проверить, может ли быть найдено представление. К тому времени, когда появится возможность добавить представление в эту коллекцию, она уже будет содержать стандартный механизм визуализации Razor. Во избежание конфликта с этой реализацией мы вызываем метод Clear() для удаления любых уже зарегистрированных механизмов, а затем метод Add() для регистрации специальной реализации.
Чтобы продемонстрировать изменения, внесенные в местоположения для поиска, была создана папка /Views/Common, а нее добавлен файл представления по имени List.cshtml. Содержимое этого файла приведено в примере ниже:
@{
ViewBag.Title = "List";
}
<em>Это файл представления <b>~/Views/Common/List.cshtml</b></em>
Чтобы отобразить это представление, в контроллер Home добавлен новый метод действия, как показано в примере ниже:
using System;
using System.Web.Mvc;
namespace WorkingWithRazor.Controllers
{
public class HomeController : Controller
{
// ...
public ViewResult List()
{
return View();
}
}
}
Если запустить приложение и перейти на URL вида /Home/List, то для обнаружения файла представления List.cshtml в папке /Views/Common будут использоваться специальные местоположения:
Добавление динамического содержимого к представлению Razor
Основная цель представлений - позволить визуализацию частей модели предметной области в виде пользовательского интерфейса. Для этого необходимо иметь возможность добавления к представлениям динамического содержимого. Такое содержимое генерируется во время выполнения, и оно может быть разным для каждого запроса.
Его противоположностью является статическое содержимое вроде HTML-разметки, которое создается во время написания кода приложения и одинаково для всех запросов. Добавлять динамическое содержимое к представлениям можно различными способами которые описаны ниже:
- Встраиваемый код Razor
Используется для небольших и независимых порций логики представления, таких как операторы if и foreach. Это фундаментальное средство для создания динамического содержимого в представлениях, на котором построен ряд других подходов.
- Вспомогательные методы HTML
Используются для генерации одиночных HTML-элементов или небольших их коллекций, обычно основанных на значениях модели или данных представления. Инфраструктура MVC Framework включает множество полезных вспомогательных методов HTML, и можно также легко создавать собственные методы подобного рода. Любой метод, возвращающий объект MvcHtmlString, может служить вспомогательным методом HTML.
- Разделы компоновки
Используются для создания разделов содержимого, которые будут вставляться в специфические позиции внутри компоновки.
- Частичные представления
Применяются для совместного использования подразделов компоновки представления между набором представлений. Частичные представления могут содержать встраиваемый код, вспомогательные методы HTML и ссылки на другие частичные представления. Частичные представления не вызывают метод действия, поэтому они не могут использоваться для выполнения бизнес-логики.
- Дочерние действия
Применяются для создания многократно используемых элементов управления или виджетов пользовательского интерфейса, которые должны содержать бизнес-логику. Дочернее действие вызывает метод действия, визуализирует представление и помещает результат в поток ответа.
Три последних приема будут рассмотрены в последующих статьях.