Ваш API и Модели Представления не Должны Использовать Модели Домена
Вы должны быть осторожны с тем, что вы раскрываете в своих клиентских моделях. Модели, предоставляемые клиенту, обычно находятся на уровне пользовательского интерфейса как ViewModels или ApiModels. Их также можно назвать DTO (Domain Transfer Objects - Объекты Передачи Данных). В любом случае они не должны напрямую ссылаться на типы из модели предметной области.
Чтобы понять, почему, давайте посмотрим, почему мы вообще используем DTO и ViewModels/ApiModels. Зачем несколько типов для описания того, что в системе, скорее всего, представляет одно и то же? Допустим, у меня есть веб-сайт, где пользователи могут проходить тесты. У каждого теста есть название, описание и набор вопросов. Моя модель предметной области для теста включает в себя некоторую бизнес-логику чтобы удостовериться, что в тесте есть хотя бы один вопрос, вопросы не повторяются и т.п.
Мне нужно, чтобы администратор мог добавить новый тест или обновить существующий. Я не хочу предоставлять доступ ко всем свойствам теста. Например, чтобы тест можно было создать с любым названием. А у созданного теста нельзя было изменить название, но можно менять описание или вопросы. Я создам типы ViewModel или ApiModel для конкретной операции, которую выполняет пользователь. Для создания теста может использоваться такой класс:
public class CreateTestViewModel {
public string Name {get;set;}
public string Description {get;set;}
}
А реальная сущность домена для теста могла бы выглядеть так:// BaseEntity<T> определяет тип поля Id
public class Test : BaseEntity<Guid> {
public string Name { get; set; }
public string Description { get; set; }
public ApplicationUser Author { get; set; }
public List<Exercise> Exercises { get; set; }
}
Если бы вместо CreateTestViewModel использовался тип Test, конечные пользователи потенциально могли бы получить доступ к полному состоянию объекта Test. Привязка модели сопоставит все данные JSON или формы с данными модели. В документации к API может быть сказано, что должны передаваться только название и описание, но злоумышленник может угадать другие свойства сущности домена и изменять их, передавая значения. Если серверный код написан небрежно, он молча примет всё, что отправляет пользователь, и сохранит данные в хранилище с помощью простых команд EF, таких как Add() и SaveChanges().
Если вы пишете код API и хотите помочь своим конечным пользователям, предоставив им полезную живую документацию, обратите внимание на Swagger и связанные с ним инструменты. Используя Swagger, вы можете предоставить конечную точку в веб-приложении, которая обеспечит интерактивное представление всех ваших публичных конечных точек API и их сигнатур. Используя модели DTO, вы можете сделать свой API максимально простым и облегчить жизнь его потребителям, сократить объём данных, передаваемых по сети, и улучшить производительность, предоставляя максимально компактные модели API.
Ещё одна причина использовать DTO - это сериализация. Часто типы моделей предметной области имеют закрытые конструкторы по умолчанию и неизменяемые свойства, которые получают значения только при создании экземпляра. Если вы попытаетесь использовать эти типы в API или в привязке модели MVC, вы, вероятно, столкнетесь с проблемами десериализации, поскольку у этих типов нет публичного конструктора по умолчанию.
Следите за Выражениями Using
Самый простой способ избежать проникновения модели предметной области в DTO - посмотреть на операторы using в этих классах. Часто ссылки на модели предметной области попадают в ваши DTO, потому что они добавляются как свойства:
public class TestDTO {
//…
public List<Exercise> Exercises { get; set; }
}
Убедитесь, что типы свойств сами являются DTO. Следите за тем, чтобы пространство имён домена не использовалось в определениях классов DTO. Можно следить за этим вручную или создать правило в таком инструменте, как NDepend.
Источник: https://www.c-sharpcorner.com/blogs/attributes-for-record-properties-in-c-sharp-9