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

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

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

Жизнь до AutoMapper

Перед тем, как начать использовать AutoMapper, давайте создадим функционал без него. Вероятно мы заметим некоторые сложности, которые сможет разрешить AutoMapper. Поиск повторяющегося кода, логика в представлениях и скучная работа с глубокими иерархиями объектов – основные моменты, которые мы хотим разгрузить.

Представьте себе представление, которое демонстрирует информацию о клиенте. В главе 2 мы обсуждали некоторые тривиальные приложения, в которых можно использовать постоянные объекты доменной модели в качестве источника данных. Следующий листинг демонстрирует такой сценарий.

Листинг 11-1: Доменная модель
@model Core.Model.Customer

<h2>Customer: @(Model.Name.First + " " + Model.Name.Middle + " " + Model.Name.Last) </h2>
<div class="customerdetails">
	<p>Status: @Model.Status </p>
	<p>
		Total Amount Paid: $
		@Model.GetTotalAmountPaid()
	</p>
	<p>
		Address: @Model.ShippingAddress.Line1,
		@Model.ShippingAddress.Line2,
		@Model.ShippingAddress.City,
		@Model.ShippingAddress.State.DisplayName
		@Model.ShippingAddress.Zip
	</p>
</div>

Строка 3: Форматирует сложные компоненты

Строки 7-8: Применяет стандартное форматирование

Строки 13-14: Глубоко рассматривает доменные объекты

Эта разметка чересчур сложна для простого содержимого, которое она демонстрирует. Она включает в себя общие правила форматирования, такие как применение знака доллара в значениях decimal и какое-то подозрительное форматирование имен, которое явно будет выглядеть неправильно, если будет отсутствовать middle name.

При отображении страницы существует не только опасность того, что она будет выглядеть неправильно, но и того, что она не будет отображаться вообще. Что если ShippingAddress содержит null? Мы увидим неприятное исключение при обращении к null на желтом экране смерти, который сопровождает основные ошибки ASP.NET. Все эти проблемы появляются потому, что представления непосредственно зависят от доменной модели - и пользовательский интерфейс знает слишком много о базовой логике программы.

Из примеров главы 2 и предыдущего раздела мы знаем, что в большинстве случаев лучше разработать пользовательскую модель специально для представления. Преобразование из доменной модели, или ее проекция в презентационную модель – прямая задача программирования. Возьмите значения из объекта-источника и скопируйте их в правильное место целевого объекта. Добавьте немного форматирующего и выравнивающего кода, и проекция готова. Такую логику можно легко протестировать.

Вот пример самодельного маппера.

Листинг 11-2: Преобразование объектов вручную
public class CustomerInfoMapper
{
	public CustomerInfo MapFrom(Customer customer)
	{
		return new CustomerInfo
		{
			Id = customer.Id,
			Name = new NameFormatter().Format(customer.Name),
			ShippingAddress = new AddressFormatter().Format(customer.ShippingAddress),
			Status = customer.Status ?? string.Empty,
			TotalAmountPaid = customer.GetTotalAmountPaid().ToString("c")
		};
	}
}

Строка 3: Принимает исходный тип, возвращает нужный

Строки 7-11: Выполняет маппинг вручную

Класс в листинге 11-2 можно протестировать, и он отделяет представление от сложности доменной модели. С его помощью представление получает данные в той форме, в которой они должны быть выведены.

Вот наше представление, обновленное для работы с CustomerInfo вместо Customer.

<h2>Customer: @Model.Name</h2>
<div class="customerdetails">
	<p>Status: @Model.Status</p>
	<p>Total Amount Paid: @Model.TotalAmountPaid</p>
	<p>Address: @Model.ShippingAddress</p>
</div>

Так гораздо лучше. Предыдущая разметка содержит больше что и где, и меньше указаний как.

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

Теперь мы понимаем, какие проблемы решает AutoMapper, и можем начать использовать его для решения задач преобразования. AutoMapper позволяет отказаться от кода ручного преобразования и дает нам возможность включить общие или специальные пользовательские правила форматирования. Вместо обязательного кода, который мы писали в листинге 11-2, мы можем объявить преобразование, и AutoMapper представит для нас соответствующее поведение.

Декларативное vs. императивное программирование

Императивное программирование подразумевает традиционный код, который мы обычно пишем. Он выражает действия в виде серии строк кода, указывающих логическую последовательность и назначение. Императивный код состоит из сложных алгоритмов и логических утверждений, которые указывают точную последовательность операций.

С другой стороны, декларативное программирование указывает, что должно быть сделано, а не как это сделать. Декларативных код прост - это просто утверждение, а не набор инструкций.

Канонический пример декларативного программирования - это регулярные выражения. Представьте воспроизведения текстового поиска, представленное сложным регулярным выражением с императивными операторами if и циклами. Избежать этого бремени (и найти эффективные инструменты) - путь к быстрому созданию и беспрепятственной поддержке.

Вот пример объявления конфигурации AutoMapper:

CreateMap<Customer, CustomerInfo>()
	.ForMember(x => x.ShippingAddress, opt =>
	{
		opt.AddFormatter<AddressFormatter>();
		opt.SkipFormatter<HtmlEncoderFormatter>();
	});

Мы вернемся к этому коду и разберем код конфигурации AutoMapper далее в этой главе.

или RSS канал: Что новенького на smarly.net