TimeCoder
@TimeCoder

Как правильно использовать DTO в реальных проектах asp.net core WebAPI?

Доброго времени,
с принципами SOLID в общем, и использовании DI-контейнеров, слоев, разных архитектур все понято. Вопрос более сложный, про то, как это работает в больших крутых проектах, с поправкой, что речь именно о WebAPI на базе asp.net core. Думаю, что многим будет интересно прочитать ответы, кто какие подходы использует.

У меня по совокупности практики и теории сложилась такая картина (Business, Data - это папки, остальное проекты, все это в одном солюшене):
Data
|___Project.Data.Contracts
|___Project.Data.Impl
Business
|___Project.Services.Contracts
|___Project.Services.Impl
WebApi
Смысл в том, что все сервисы и репозитории регистрируются в DI, и могут быть использованы в любом месте.
Общая логика такова:
1. В контроллер прилетает запрос, код метода почти из одной строки: идет вызов метода из нужного сервиса. Еще можем тут же проверять авторизацию.
2. В сервисе вся логика, основной код, и там же дергаются репозитории.

Вот теперь самое главное. На простом примере, пусть сущность User.
Есть UserController в WebApi, в слое сервисов, допустим, только логика, объекта User нет. Он есть в слое DAL, причем в Project.Data.Contracts находится IUser, а в Project.Data.Impl - просто User. Понятно, что вот этот User содержит "database-specific" обвески, например, атрибуты EntityFramework. Мы не можем этот объект выпускать за пределы слоя данных, репозиторий отдает, конечно, его под видом IUser. Но что мы используем на уровне WebApi? Нужна ли в данном случае своего рода ViewModel?

Другими словами: нужен ли еще один класс, реализующий IUser, используемый как DTO в работе самого WebAPI?

Понятно, что он может и не наследовать IUser (просто конвертировать AutoMapper'ом). Мне видится, что он нужен (его будет получать или возвращать контроллер), но вот код дублируется. Получается 3 почти идентичных куска кода: IUser, User (DB), UserViewModel (WebApi).

Есть немного другой путь: не использовать EntityFramework (вполне реальные кейсы), взять, например, Dapper. Там в классе User не будет атрибутов, он будет чистым DTO. И теоретически, мог бы использоваться в WebAPI, но тогда придется сделать прямую ссылку на Project.Data.Impl. Точнее говоря, эта ссылка и так есть (нам же надо в Startup.cs зарегистрировать все репозитории, а DI из коробки asp.net core не поддерживает модули и их сканирование, в отличие от Ninject), но архитектурно это не правильно. Если только не вынести такие объекты в еще один проект.

Спасибо, что дочитали)
  • Вопрос задан
  • 5411 просмотров
Решения вопроса 2
qonand
@qonand
Software Engineer
Другими словами: нужен ли еще один класс, реализующий IUser, используемый как DTO в работе самого WebAPI?

В Вашей ситуации слой сервисов должен возвращать в WebApi DTO, но реализовывать его как IUser не стоит. Разделение системы на слои подразумевает что каждый слой может знать только о нижележащем слое (точнее о его интерфейсах). Если DTO, возвращаемое в WebAPI, будет реализовывать IUser относящийся к DAL произойдет нарушение порядка слоев, что как бы ни разу не тру.
Получается 3 почти идентичных куска кода: IUser, User (DB), UserViewModel (WebApi).

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

Есть немного другой путь: не использовать EntityFramework (вполне реальные кейсы), взять, например, Dapper. Там в классе User не будет атрибутов, он будет чистым DTO. И теоретически, мог бы использоваться в WebAPI, но тогда придется сделать прямую ссылку на Project.Data.Impl.

Если User останеться в DAL - тогда проблема не решиться, у Вас по прежнему будет нарушение порядка слоев ...
Ответ написан
AlexanderByndyu
@AlexanderByndyu
IT-архитектор, эксперт в Agile&Lean
TimeCoder я подробно рассматривал этот вопрос в статье blog.byndyu.ru/2012/05/viewmodel-domain-model.html

Если останутся вопросы, буду рад ответить.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы