ASP.NET MVC 3: проверка модели, когда требуется информация, внешняя по отношению к модели

Какой хороший способ проверить модель, когда информация, внешняя по отношению к модели, требуется для проверки правильности? Например, рассмотрим следующую модель:

public class Rating {
    public string Comment { get; set; }
    public int RatingLevel { get; set; }
}

Затем системный администратор может установить RatingLevels, для которого требуется комментарий. Эти настройки доступны через службу настроек.

Итак, для полной проверки модели мне нужна внешняя информация, в этом случае служба настроек.

Я рассмотрел следующее:

  • Ввести услугу в модель. DefaultModelBinder использует System.Activator, чтобы создать объект, чтобы он не проходил через обычный преобразователь зависимостей, и я не могу внедрить эту услугу в модель без создания нового связующего устройства (кроме того, что не похоже на правильный способ сделать это).
  • Внесите сервис в аннотацию. Я еще не уверен, что это возможно, но скоро расследуем. Он все еще чувствует себя неуклюжим.
  • Использовать настраиваемое связующее устройство. По-видимому, я могу реализовать OnPropertyValidating, чтобы выполнить выборочную проверку свойств. Это кажется наиболее предпочтительным до сих пор, хотя я еще не уверен, как это сделать.

Какой метод, выше или не выше, лучше всего подходит для такого типа проверки?

Ответы

Ответ 1

Вариант 1 не подходит. Единственный способ, которым это будет работать, - это затянуть зависимость с помощью анти-шаблона локатора сервиса.

Вариант 2 не работает.. Хотя я не мог понять, как это возможно из-за требований атрибутов С#, это возможно. См. Следующие ссылки:

Вариант 3: Я не знал об этом раньше, но то, что кажется очень мощным способом написания валидаторов, заключается в использовании ModelValidator и соответствующий ModelValidatorProvider.

Сначала вы создаете свой собственный ModelValidatorProvider:

public class CustomModelValidatorProvider : ModelValidatorProvider
{
    public CustomModelValidatorProvider(/* Your dependencies */) {}

    public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
    {
        if (metadata.ModelType == typeof(YourModel))
        {
            yield return new YourModelValidator(...);
        }
    }
}

ASP.NET MVC IDependencyResolver будет пытаться разрешить вышеупомянутый провайдер, поэтому, пока он зарегистрирован в вашем контейнере IoC, вы выиграли ' нужно делать что-нибудь еще. И затем ModelValidator:

public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator
{
    public EntryRatingViewModelValidatorMvcAdapter(
            ModelMetadata argMetadata,
            ControllerContext argContext)
                : base(argMetadata, argContext)
    {
        _validator = validator;
    }


    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
        if (/* error condition */)
        {
            yield return new ModelValidationResult
              {
                MemberName = "Model.Member",
                Message = "Rating is required."
              };
        }
    }
}

Как поставщик получает через IDependencyResolver, и поставщик имеет полный контроль над возвращенным ModelValidator, я легко мог вставлять зависимости и выполнять необходимую проверку.

Ответ 2

Вы можете попробовать свободно проверять. Он поддерживает asp.net mvc и DI, чтобы вы могли вводить внешние службы в свои валидаторы.

Ответ 3

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

Я даю несколько примеров кода в ответе этого вопроса о добавлении валидаторов в модель. Единственным дополнительным шагом в вашем случае является то, что вам нужно будет внедрить вашу службу в свой класс, наследующий от DataAnnotationsModelValidatorProvider.