Проверка сервисного уровня - PullRequest
14 голосов
/ 13 декабря 2011

Я пытаюсь реализовать стратегию проверки в моем приложении. У меня есть уровень MVC, уровень обслуживания, репозиторий и домен POCO. Теперь на уровне MVC я использую аннотации данных на моих моделях просмотра для проверки ввода пользователя, что позволяет мне быстро дать пользователю обратную связь. В контроллере я вызываю ModelState.IsValid, чтобы проверить входные данные, прежде чем использовать automapper для настройки объекта домена.

Вот где моя проблема. Я передаю свой доменный объект в Службу, которая должна проверить его в соответствии с моими бизнес-правилами, но как передать ошибки проверки обратно контроллеру? Примеры, которые я нашел, делают одно из следующего:

  • Создайте исключение в слое Service и поймайте в Contoller. Но это кажется неправильным, конечно, исключения сделаны для исключительных случаев, и мы должны вернуть что-то значимое.
  • Используйте ModelStateWrapper и вставьте ModelStateDictionary в Сервис. Но этот метод в конечном итоге разворачивается в циклическую зависимость (контроллер зависит от службы, служба зависит от контроллера), и это, кажется, является неприятным запахом кода.
  • Добавить метод проверки в POCO. Проблема заключается в том, что бизнес-правило может опираться на другие объекты POCO, поэтому, безусловно, это следует делать в службе, имеющей доступ к необходимым таблицам и объектам.

Есть ли более простой метод, который мне не хватает? Я видел много вопросов по этому поводу, но никакого конкретного решения кроме упомянутых выше Я думаю, что любой метод в Сервисе, который выполняет проверку, мог бы просто вернуть некоторый объект ключ / значение, который я могу использовать в контроллере, но не уверен, что эта стратегия может быть проблематичной в дальнейшем.

Ответы [ 2 ]

13 голосов
/ 13 декабря 2011

Я думаю, что довольно элегантным способом было бы иметь метод validate в вашем сервисе, который возвращает словарь ошибок модели из бизнес-логики. Таким образом, не происходит внедрения ModelState в службу - служба просто выполняет проверку и возвращает любые ошибки. Затем контроллер должен объединить эти ошибки ModelState обратно в его ViewData.

Таким образом, метод проверки сервиса может выглядеть следующим образом:

public IDictionary<string, string> ValidatePerson(Person person)
{
    Dictionary<string, string> errors = new Dictionary<string, string>();

    // Do some validation, e.g. check if the person already exists etc etc

    // Add model erros e.g.:
    errors.Add("Email", "This person already exists");
}

И затем вы можете использовать метод расширения в вашем контроллере для отображения этих ошибок в ModelState, что-то вроде:

public static class ModelStateDictionaryExtensions
{
    public static void Merge(this ModelStateDictionary modelState, IDictionary<string, string> dictionary, string prefix)
    {
        foreach (var item in dictionary)
        {
            modelState.AddModelError((string.IsNullOrEmpty(prefix) ? "" : (prefix + ".")) + item.Key, item.Value);
        }
    }
}

И ваш контроллер будет использовать:

ModelState.Merge(personService.ValidatePerson(person), "");
2 голосов
/ 20 февраля 2016

В качестве альтернативы созданию промежуточного словаря, предложенного Ианом, вы также можете сделать это с помощью валидатора, который принимает функцию.

например. в слое обслуживания:

public void ValidateModel(Customer customer, Action<string, string> AddModelError)
{
  if (customer.Email == null) AddModelError("Email", "Hey you forgot your email address.");
}

Затем в вашем контроллере вы подтверждаете одним вызовом:

myService.ValidateModel(model, ModelState.AddModelError);

Или, если вы хотите использовать свой валидатор в консольном приложении без доступа к ModelStateDictionary, вы можете сделать это:

errors = new NameValueDictionary();
myService.ValidateModel(model, errors.Add);

Оба они работают, потому что ModelStateDictionary.AddModelError() и NameValueDictionary.Add() сопоставить сигнатуру метода для Action<string, string>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...