Проверка данных на уровне сервиса на соответствие DTO, моделям сущностей или чему-то еще?

Я работаю над проектом ASP.NET MVC. В проекте у меня есть уровень обслуживания, который принимает DTO для операций CRUD. Когда мне нужно проверить бизнес-логику, должен ли валидатор принимать DTO, модели сущностей или что-то еще?

Например:

public class ProductService: IProductService
{
    public ValidationResult CreateProduct(ProductDTO productDto)
    {
       //call productValidator.Validate(productDto) on the DTO here?

        Product productEntityModel = mapper.Map<Product>(productDto);

        //or, call productValidator.Validate(productEntityModel) on the Entity model here?

        if(validationResult.Valid)
        {
            _dbContext.Products.Add(productEntityModel);
            _dbContext.SaveChanges();
        }

        return validationResult
    }
}

Некоторые мысли:

  • Я видел в Интернете некоторые разговоры о создании POCO, который может иметь логику проверки (вместо использования службы проверки) и даже другую бизнес-логику внутри нее. В этом есть смысл, но это еще одно «представление» продукта, которым нужно управлять и поддерживать.
  • Проверка на соответствие DTO может показаться немного более разумной, поскольку это то, что вызывающий абонент отправляет в службу?

Спасибо за помощь!!


person John-Luke Laue    schedule 28.07.2017    source источник
comment
Я использую подход DTO, и у меня есть вопрос. Как бы вы вернули ошибку проверки, если подпись вашего метода List<History> ListHistory(int userId, string specialString)?   -  person Ozgur    schedule 25.01.2018


Ответы (1)


Когда мне нужно проверить бизнес-логику, должен ли валидатор принимать DTO, модели сущностей или что-то еще?

Обычно мы выполняем проверку в ViewModel классе с помощью DataAnnotations, чтобы мы могли вернуть удобный для пользователя ModelError. Например,

public class LoginViewModel
{
   [Display(Name = "Username")]
   [Required(ErrorMessage = "Please enter your username.")]
   public string UserName { get; set; }
}

public async Task<ActionResult> Login(LoginModel model, string returnUrl)
{
   if (ModelState.IsValid)
   {
      ...
      ModelState.AddModelError("", "User is not authorized!");
   }
   ...
}

Хотя вы можете проверить некоторую бизнес-логику внутри ProductService, вы не можете вернуть MVC ModelError, поскольку уровень службы / репозитория не должен зависеть от ASP.NET MVC (или любых компонентов пользовательского интерфейса).

Большая часть ошибок на уровне службы / репозитория - это неожиданная ошибка, а не ошибка пользователя. Мы не регистрируем эту ошибку в NLog или Log4Net и перенаправляем пользователя на настраиваемую страницу ошибок.

person Win    schedule 28.07.2017
comment
Я должен был указать глубокую / сложную логику, которая требует доступа к базе данных, а не простой проверки, такой как обязательные поля. Например, проверка того, что другой продукт с таким же именем еще не существует в базе данных. - person John-Luke Laue; 29.07.2017
comment
Мне лично нравится хранить бизнес-логику внутри метода действий. Мне нравится, что мой уровень сервиса / репозитория максимально чистый. Взгляните на одну из лучших корзин с открытым исходным кодом на основе ASP.NET MVC - Создать метод действия и метод InsertCustomer внутри класса Repository / Service. - person Win; 29.07.2017
comment
Ах, мне лично нравится бизнес-логика внутри проекта службы или ядра, а не проекта сети / презентации. Если необходимо добавить еще один уровень представления или использовать отдельный API, я не хочу дублировать логику. - person John-Luke Laue; 29.07.2017
comment
Нет правильного или неправильного ответа. Похоже, вы готовы принять решение; Я скажу, давай. - person Win; 29.07.2017