□ Из действия контроллера можно обратиться к представлению, находящемуся в любой из директорий, указав полный путь к представлению. Аналогично, представление может использовать частичные представления, размещенные в разных директориях, с указанием полного пути к ним, однако такой подход приводит к путанице, и мы настоятельно рекомендуем группировать представления, относящиеся к одному контроллеру, в одну директорию.
□ В случае, когда нескольким контроллерам может понадобиться использовать одну и ту же разметку представления, стоит подумать о будущем развитии проекта и выбрать один из двух путей.
□ Разметка всегда будет одинакова для обоих контроллеров — в этом случае представление следует разместить в директории Shared.
□ Разметка может в будущем различаться — в этом случае общую разметку следует вынести в файл частичного представления и поместить в директорию Shared, а для каждого из контроллеров создать собственное представление. Не стоит смущаться, если в начале разработки проекта каждое из представлений будет содержать только ссылку на общее частичное представление — в будущем будет значительно проще модифицировать представления для контроллеров, если избежать слияния разметки в самом начале развития проекта.
□ Директория Views предназначена только для файлов представлений, обрабатываемых механизмом генерации представлений, статические файлы, используемые на страницах (js, .css, изображения), следует размещать в других директориях. Например, в шаблонном проекте MVC Application, создаваемом Visual Studio, предлагается использовать для статических файлов директорию Content, а для скриптов .js директорию Scripts. Здесь уже выбор может определяться полностью вашим вкусом. Неплохой идеей может быть создание директории Content с вложенной структурой директорий, повторяющей структуру директории Views, где статические файлы будут размещены по тому же принципу, что и в директории Views. Возможно, что вам будет удобнее создать иную структуру директорий и группировать статические файлы не по принадлежности к представлениям, а по расположению звезд на небосклоне или какой-либо другой логике.
Данные для отображения и ViewData
В главе 1 кратко был описан механизм передачи данных от контроллера представлению. Поскольку основной задачей представления является отображение данных, мы подробно остановимся на этой теме.
ViewData — это класс типа viewDataDictionary, из названия типа которого очевидно, что ViewData представляет собой коллекцию типа ключ-значения, называемую словарем.
public class ViewDataDictionary : IDictionary<string, object> {}
Поскольку ViewData является коллекцией доступных по строковому ключу объектов, в ней может быть сохранено произвольное количество объектов разных типов.
public ActionResult ViewDataDemo()
{
ViewData.Add("Hello", "World");
ViewData["Date"] = DateTime.Now;
return View();
}
Объекты, содержащиеся в коллекции ViewData, в свою очередь, могут быть использованы в разметке представления.
<p><%= ((DateTime)ViewData["Date"]).ToLongTimeString() %></p>
Строгая типизация данных представления
Работа с произвольным набором элементов удобна, когда набор данных, отображаемых представлением, меняется в процессе развития проекта. Однако в случаях, когда все данные представления могут быть описаны одним классом, значительно удобнее использовать строго типизированные представления. Для этого коллекция ViewData предоставляет свойство ViewData.Model и возможность строгой типизации представления путем наследования самого класса представления от класса ViewPage<T>. В листинге 5.4 представлена разметка строго типизированного представления.
Листинг 5.4. Представление ViewDataModelStronglyTyped.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcViewsDemo.Models.Customer>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
ViewDataModelStronglyTyped
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
ViewDataModelStronglyTyped
</h2>
<fieldset>
<legend>Fields</legend>
<p>
CompanyName:
<%= Html.Encode(Model.CompanyName) %>
</p>
<p>
ContactName:
<%= Html.Encode(Model.ContactName) %>
</p>
<p>
ContactTitle:
<%= Html.Encode(Model.ContactTitle) %>
</p>
<p>
Address:
<%= Html.Encode(Model.Address) %>
</p>
</fieldset>
</asp:Content>
С точки зрения контроллера, для работы со строго типизированным представлением достаточно присвоить объект свойству ViewData.Model либо передать объект в качестве параметра методу View ().
public ActionResult ViewDataModelStronglyTyped()
{
NorthwindDatabase db = new NorthwindDatabase();
return View(db.GetCustomers().First());
}
В случае нестрого типизированного представления объект также может быть передан в свойство ViewData.Model, однако это не имеет практической пользы, поскольку на стороне представления все равно придется выполнять приведение типов для свойств этого объекта.
Преимущества строго типизированного представления очевидны — поддержка подсказки IntelliSense при разработке представлений в Visual Studio, возможность генерации заготовок представлений средствами Visual Studio, как это было выполнено для представления, приведенного в листинге 5.4.
В строго типизированном представлении также доступна коллекция объектов viewData, поэтому даже при использовании строгой типизации количество элементов данных, используемых представлением, может быть модифицировано при развитии проекта.
Некоторые разработчики предпочитают для каждого из представлений создавать отдельный класс данных, с помощью которого типизировать представления. Некоторые же предпочитают использовать строгую типизацию только для того, чтобы передавать объекты в частичные представления, работая с коллекцией viewData в разметке самих представлений. Выбор определяется предпочтениями разработчиков проекта.
Поиск элементов в коллекции ViewData
Легко представить себе ситуацию, в которой на стороне представления заранее не определено, где находятся данные — в коллекции viewData или же в свойствах объекта viewData.Model. Для поиска этого элемента доступен специальный метод viewData.Eval(), осуществляющий поиск в коллекции элементов и в свойствах объекта модели, при этом поддерживается синтаксис точки (.) между именами свойств объектов.
Например, в представлении используется метод viewData.Eval("customer. lastname"), тогда будет выполнен поиск элемента по описанному далее алгоритму.
1. Будет проверено наличие значения ViewData["customer. lastname"].
2. Если значение отсутствует для приведенного ранее элемента коллекции, то будет осуществлен поиск элемента ViewData["customer"] .
3. В случае если элемент найдет по ключу "customer", то будет осуществлена попытка получить значение ViewData["customer"].lastname, если же такого свойства у объекта, содержащегося под ключом "customer", найдено не будет, будет осуществлена попытка найти элемент вложенной коллекции ViewData["customer"]["lastname"].