Проверка в многоуровневом приложении ASP.NET Core - PullRequest
0 голосов
/ 15 мая 2018

Я разрабатываю многоуровневое веб-приложение со слоем MVC, Service и Repository, однако мне сложно понять, где разместить логику проверки, которая позволяет мне использовать преимущества встроенной проверки формы .NET Core (например, ModelStateDictionary), следуя принципу СУХОЙ.

first и наиболее очевидный подход заключается в использовании ViewModel, который имеет соответствующие аннотации данных:

public class VendorViewModel
{

    public long Id { get; set; }

    [Required]
    public string Name { get; set; }


    [Required]
    public string Phone { get; set; }


    [Required]
    public string Email { get; set; }


    [Required]
    public string Address { get; set; }


    public DateTime? VerifiedAt { get; set; }

}

Тогда действие моего контроллера будет выглядеть так:

   public async Task<IActionResult> Create([FromForm] VendorViewModel model)
    {
        await AuthorizePolicyAsync(AuthorizationPolicyTypes.Vendor.Create);
        if (!ModelState.IsValid) //Validation problems, so re-display the form.
            return View(model);

        await _vendorservice.CreateVendorAsync(model.Name,model.Phone,model.Email,model.Address,null);
        return RedirectToAction(nameof(Index));
    }

Это работает нормально, однако есть пара проблем:

  1. Это поддерживает только базовую проверку, такую ​​как проверка длины символа и т. Д.В приведенном выше конкретном примере я хочу проверить, что model.Address является действительным адресом в соответствии с картами Google, а также содержит город, о котором известно приложению, что означает, что этот вид проверки должен быть перемещен на уровень обслуживания, чтобы сохранитьКонтроллер "тонкий".
  2. На уровне сервиса теперь отсутствует какая-либо логика проверки и предполагается, что он всегданг передал действительные данные.Мне кажется, что это неправильно, поскольку уровень обслуживания должен отвечать за поддержание системы в согласованном действительном состоянии.Решением этой проблемы было бы также добавить логику проверки к уровню обслуживания, но, по моему мнению, это нарушает принцип DRY.

Подход second заключается в перемещениивсю логику проверки на сервисном уровне и переместить все мои аннотации данных в фактический объект домена Vendor.Таким образом, каждая операция может проверять модель на основе аннотаций данных, а также применять более сложную логику, такую ​​как проверка адреса с помощью карт Google, как упоминалось ранее.Однако я не уверен, как я могу проверить аннотированный объект таким же образом, как это делает MVC Controller, и передать обратно словарь в контроллер.Эта функциональность, по-видимому, специфична для MVC и привнесет зависимость от MVC на моем уровне обслуживания, что нежелательно.

В любом случае я могу элегантно перенести логику проверки на уровень обслуживания, используя преимущества аннотаций данных и MVCвстроенный ModelStateDictionary?Как мне вернуть список ошибок обратно в контроллер?Выдать ли исключение и перехватить его в контроллере, если возникнут какие-либо ошибки проверки?

Я видел несколько вопросов, задающих аналогичный вопрос, но я не удовлетворен ни одним из ответов.Другие ответы, похоже, предполагают написание логики проверки вручную и не используют аннотации данных.Это то, к чему я должен прибегнуть?

1 Ответ

0 голосов
/ 15 мая 2018

Вы можете создавать свои собственные пользовательские атрибуты проверки в дополнение к тем, которые доступны из коробки, такие как Required, Range, StringLength и т. Д. Я приведу пример ниже:

public class ValidateAddressAttribute : Attribute, IModelValidator
{
    public bool IsRequired => true;
    public string ErrorMessage { get; set; } = "Address is not valid";

    public IEnumerable<ModelValidationResult>Validate(ModelValidationContext context) 
    {
       List<ModelValidationResult> validationResults = new List<ModelValidationResult>();
       string address = context.Model as string;
       if(!IsAddressValid(address))
       {
         validationResults.Add(new ModelValidationResult("", ErrorMessage));            
       }
       return validationResults;

    }

    private bool IsAddressValid(string address)
    {
       bool isAddressValid;
       //set isAddressValid to true or false based on your validation logic
       return isAddressValid;
    }
}

Теперь вы можете применить этот атрибут к свойству адреса следующим образом:

[Required]
[ValidateAddress(ErrorMessage="Invalid Address")]
public string Address { get; set; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...