Где конвертировать DTO в ViewModel?
Я унаследовал проект MVC2, используя довольно стандартный и прилично хорошо сохранившийся шаблон DDD. Я тоже много читал на всех дискуссиях DTO/ViewModel.
В настоящее время наши DTO часто используются как ViewModels. Это честно не влияет на то, что мы делаем, но я бы хотел использовать правильные ViewModels при обновлении сайта.
Здесь мой вопрос:
Наши модели проектов "домен" в настоящее время содержат объекты и возвращают DTO для моих контроллеров. Теперь мне нужно сопоставить этот DTO с ViewModel. Где я должен это делать?
- Прямо в контроллере?
- В проекте домена?
- В другом месте?
Я сохраняю свои ViewModels вместе с представлениями в нашем проекте "Веб", поэтому неправильно конвертировать DTO → ViewModel в проект домена. Он также чувствует себя неправильно, делая это в контроллере.
Что сделали другие?
Edit:
Этот вопрос/ответ предлагает обработать его в контроллере. Конечно, это легко понять.
Ответы
Ответ 1
DTO обычно являются специфичными для технологии. Например, в мире .NET ваши DTO, вероятно, украшены атрибутами сериализации DataContract
и DataMember
. Более того, DTO вместе с сервисом, который возвращает их, образуют адаптер для домена в терминах шестиугольной архитектуры. Они адаптируют ваш домен к определенной транспортной технологии, такой как HTTP, и поэтому они живут за пределами вашего домена. Другими словами, домен не должен обладать знаниями о DTO - DTO должны быть определены в отдельном проекте. Проект, содержащий службу, должен иметь код сопоставления, который отображает объекты домена в DTO.
Проект ASP.NET MVC похож по своей природе - он адаптирует ваши службы /DTO (или объекты домена напрямую) к технологии презентации, в частности, к HTML. Таким образом, DTO не должны знать о ViewModels. Вместо этого контроллер MVC должен ссылаться на сопоставление между DTO и ViewModels. Это можно сделать разными способами, но то, что я нашел лучшим, - это конструктор в ViewModel, принимающем DTO. Кроме того, в случаях, когда действие контроллера требует создания DTO для отправки обратно в службу, ViewModel может содержать метод создания DTO на основе ViewModel. Он содержит весь код преобразования в ближайшем к ViewModel представлении - экземпляр шаблон экспертной информации. Другим способом реализации этого было бы использовать что-то вроде AutoMapper, который использует сопоставление, основанное на соглашениях, чтобы избежать кода шаблона. Все, что было за этим, я бы подумал о переполнении, если оно не вызвано.
Во многих случаях ваш ViewModel заканчивается тем же, что и DTO, но с конкретными атрибутами ASP.NET MVC для привязки и проверки. Даже если это может показаться нарушением DRY, это действительно отдельные обязанности.
Ответ 2
Во-первых, всегда используйте явные ViewModels для ваших представлений, не передавайте DTO полностью до представления. Это немного более эффективная работа, но она дает вам больше контроля над точно, какие данные необходимы в представлении (это также предотвращает использование такой структуры, как EF, из-за большого количества дополнительных данных, которые вы можете использовать или не использовать)
Во-вторых, в этой статье описывается шаблон Orchestrator http://www.simple-talk.com/dotnet/asp.net/never-mind-the-controller,-here-is-the-orchestrator/, который, вероятно, является просто другим именем для другого шаблона, но мне нравится формат.
По существу, вы создаете Orchestrator для каждого контроллера. Orchestrator принимает данные (как правило, ViewModel и любые другие базовые типы данных, в частности, из HttpContext), и возвращает ViewModel (если необходимо для представления, в противном случае какой-либо другой тип возврата).
Этот формат дает вам возможность легко unit test использовать реальную логику, не пытаясь издеваться над материалами HttpContext, которые нужны контроллерам.
Ответ 3
Похоже на то, что вы хотите делать в специально созданном классе/модуле сопоставления.
Я лично дал своему контроллеру зависимость от службы сопоставления, а затем делегировал фактическое преобразование на это, прежде чем возвращать представление с недавно созданной моделью просмотра.
public class DemoController : Controller
{
private readonly IMappingService _mappingService;
public DemoController(IMappingService mappingService)
{
_mappingService = mappingService;
}
public ActionResult Stuff()
{
var vm = _mappingService.Map(yourDto);
return View(vm);
}
}
Ответ 4
Хорошим подходом является перегрузка конструктора на ViewModel со вторым конструктором, который имеет dto в качестве параметра. Это означает, что вы можете обрабатывать отображение в самой модели просмотра. Это позволяет вашему контроллеру быть красивым и аккуратным, не настраивая службу сопоставления.