Главная страница   /   5.1. Что такое модель представления? (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

5.1. Что такое модель представления?

Назначение модели представления понятно и без объяснений - эта модель специально разработана для использования в представлении. Она предоставляет упрощенный интерфейс над доменной моделью, который сводит принятия решений в представлении к минимуму.

В этом разделе мы разберем работу модели представления на упрощенном примере интернет-магазина. Мы рассмотрим, как модель представления отличается от доменной модели и какие механизмы обеспечивают связь модели представления и самого представления. В конце главы мы изучим модели ввода, которые используются для отправки пользовательских данных от представления к контроллеру.

Пример интернет-магазина

Давайте рассмотрим простой интернет-магазин. Он может содержать такие классы, как Customer, Order и Product (что показано в листинге 5.1), которые соответствуют таблицам в реляционной базе данных и связаны с ними по технологии ORM.

Листинг 5-1: Классы Customer, Order и Product, используемые в интернет-магазине
public class Customer
{
	public int Number { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public bool Active { get; set; }
	public ServiceLevel ServiceLevel { get; set; }
	public IEnumerable<Order> Orders { get; set; }
}
public enum ServiceLevel
{
	Standard,
	Premier
}
public class Order
{
	public DateTime Date { get; set; }
	public IEnumerable<Product> Product { get; set; }
	public decimal TotalAmount { get; set; }
}
public class Product
{
	public string Name { get; set; }
	public decimal Cost { get; set; }
}

Административная часть нашего магазина может содержать страницу сводки по клиентам, которая содержит список всех клиентов и количество их заказов. Пример страницы показан на рисунке 5.1.

Один из способов создать такой интерфейс заключается в использовании доменной модели напрямую. Мы могли бы получить список клиентов из базы данных, передать его в представление, которое на его основе построит таблицу. Когда представление дойдет до последней колонки (Most Recent Order Date), ему нужно будет снова пройтись циклом по коллекции объектов Orders класса Customer, чтобы вычислить, какой заказ был самым последним.

Рисунок 5-1: Страница со списком клиентов и заказов

Единственная проблема такого подхода заключается в том, что он сильно усложняет представление. Чтобы сделать представление более регулируемым, нужно сделать его более простым – сложные циклы и расчеты должны выполняться на более высоком уровне. Единственное, что должно выполнять представление - это показывать результаты этих расчетов. Мы создадим модель, которая будет только представлять эту таблицу.

Создание модели представления

Создание модели представления для страницы сводки о клиентах - довольно простая задача. Модели представления, как правило, являются довольно простыми объектами с однообразной структурой, которые обращаются непосредственно к тем данным в БД, которые будут отображаться в пользовательском интерфейсе. В этом случае, наша модель будет просто содержать атрибут для каждого столбца в таблице, как показано в листинге 5.2.

Листинг 5-2: Класс CustomerSummary
public class CustomerSummary
{
	public string Name { get; set; }
	public string Active { get; set; }
	public string ServiceLevel { get; set; }
	public string OrderCount { get; set; }
	public string MostRecentOrderDate { get; set; }
}

Строки 3-7: Каждый атрибут соответствует столбцу таблицы

Эта модель намеренно проста, она содержит в основном строки (string). В конце концов, это именно то, что она представляет: текст на странице. Логика отображения данных в этом объекте тоже проста - представление только выводит данные. Модель представления выполняет свою основную задачу - сводит к минимуму принятие решений в представлении.

Модель для всей таблицы имеет тип IEnumerable<CustomerSummary>. В такой простой модели, как эта, представление только выполняет заданный цикл, записывая данные каждого CustomerSummary в строки. Но прежде, чем мы сможем отобразить объекты CustomerSummary, мы должны приписать им необходимые значения и заполнить их данными из нашей доменной модели.

Презентационная модель

В нашем приложении мы будем строить эту модель не один раз. Она может быть или создана путем отправки запроса к базе данных (создание простого отчета), или спроектирована из нашей доменной модели вручную либо автоматически, с помощью такого инструмента отображения, как AutoMapper (который мы рассмотрим в главе 11).

Как правило, создается специальный класс, единственная функция которого – создавать презентационную модель. Лучше строить презентационную модель в коде приложения, чем в представлении, которое должно быть сфокусировано на HTML и стилях. Специальный класс, который создает эту модель, легко программировать, тестировать и поддерживать.

Создавать презентационную модель в контроллере также не рекомендуется. Функция контроллера – вызывать представления и координировать их работу. В листинге 5.3 показан упрощенный пример того, как контроллер может отправить презентационную модель к представлению.

Листинг 5-3: Метод контроллера для презентационной модели
public class CustomerSummaryController : Controller
{
	private CustomerSummaries _customerSummaries = new CustomerSummaries();
	public ViewResult Index()
	{
		IEnumerable<CustomerSummary> summaries = _customerSummaries.GetAll();
		return View(summaries);
	}
}

Строка 9: Отправляет презентационную модель к представлению

В этом примере объект CustomerSummaries отвечает за создание презентационной модели CustomerSummary. Он отправляет запрос к доменной модели и отображает результаты в простой форме, подходящей для использования в представлении.

После того, как объекты CustomerSummary были созданы, контроллер передает их в метод View (), который передает представлению (строка 9 листинга). В ASP.NET MVC существует специальный механизм для совместного использования моделей, который мы рассмотрим в следующем пункте.

ViewData.Model

Контроллер и представление совместно используют объект типа ViewDataDictionary - ViewData. ViewData представляет собой стандартный словарь со строковыми индикаторами и значениями объектов, который также имеет атрибут Model. Когда мы вызываем return View (summaries) в листинге 5.3, ViewData.Model автоматически заполняется объектами из нашего списка CustomerSummary, подготовленными для отображения в представлении. Атрибут Model является строго типизированным, так что представление точно знает, какой результат от него ожидать. Также разработчики могут воспользоваться преимуществами IDE, такими как IntelliSense и разрешить изменение имен переменных. Большинство из этих внутренних доработок маскируются с помощью движка представлений Razor, который позволяет легко определить тип модели. Тип модели в представлении можно назначить с помощью инструкции @model:

@model IEnumerable<DisplayModel.Models.CustomerSummary>

Инструкция @model указывает, что модель представления (свойство ViewData.Model) принадлежит типу IEnumerable<CustomerSummary>. Когда мы разработали модель представления, мы можем легко сделать разметку HTML, как показано в листинге 5.4.

Листинг 5-4: Использование модели в представлении
<table>
	<tr>
		<th>Name</th>
		<th>Active?</th>
		<th>Service Level</th>
		<th>Order Count</th>
		<th>Most Recent Order Date</th>
	</tr>
	@foreach (var summary in Model)
{
	<tr>
		<td>@summary.Name</td>
		<td>@summary.Active</td>
		<td>@summary.ServiceLevel</td>
		<td>@summary.OrderCount</td>
		<td>@summary.MostRecentOrderDate</td>
	</tr>
	}
</table>

Строка 9: Определяет тип IEnumerable<CustomerSummary>

Строки 12-16: Работает с моделью

Разметка в листинге 5.4 создает таблицу. Не используя «магические» строковые индикаторы и сложную логику, мы будем работать напрямую с моделью. Разрабатывая модель отдельно и исключительно для представления, можно значительно упростить разработку приложения.

Многие интерфейсы гораздо более сложны, чем одна таблица. Они могут включать несколько таблиц, дополнительные поля с разнообразным контентом: изображения, заголовки, промежуточные итоги, графики, диаграммы и тысячу других вещей, которые усложняют представление. Модель представления создается для обработки их всех. Разработчики могут создавать и поддерживать даже самые сложные интерфейсы, когда модель представления хорошо реализована. Если интерфейс содержит несколько сложных элементов, модель представления может работать как упаковщик, объединяя все модули и значительно упрощая HTML-разметку. Хорошая модель представления не скрывает сложные элементы, но она представляет их как можно более точно и просто и отделяет от других данных на странице.

Еще одной сложной функцией веб-приложения является обработка данных, вводимых пользователем. Мы рассмотрим представление пользовательского ввода в следующей главе.