Где конвертировать 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 в качестве параметра. Это означает, что вы можете обрабатывать отображение в самой модели просмотра. Это позволяет вашему контроллеру быть красивым и аккуратным, не настраивая службу сопоставления.