Как вводить зависимости, используемые для проверки в .NET MVC3?

У нас есть довольно много методов проверки, которым необходимо получить доступ к репозиториям/базе данных для выполнения своей работы. До сих пор мы использовали шаблон локатора службы (хотя и экономно), чтобы выполнить это в пользовательских ValidationAttributes:

public override bool IsValid(object value)
{
    // use custom service locator in our app infrastructure
    var repos = DependencyInjector.Current.GetService<IXyzRepository>();
    ...
}

Я знаю, что это:( как анти-шаблон, и мы хотели бы использовать более правильный подход. Мы используем единство, и я читаю этот пост, который говорит, что нужно использовать метод наращивания. Однако ссылка в принятом ответе говорит, что документация устарела (отставной контент).

В решении нет необходимости использовать атрибут проверки, я полагаю, что он мог бы использовать документ IValidatableObject, однако проблема остается: как ввести зависимость в модель. Нужно ли нам для этого использовать специализированное связующее?

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

Также мы иногда используем [RemoteAttribute] для выполнения некоторых из этих проверок на клиенте. В настоящее время эти методы создают модель представления и делегируют валидацию модели, используя статический метод Validator.TryValidateObject.

Как вы выполнили проверку, которая требует, чтобы вложенная зависимость выполняла свою работу без использования анти-шаблона SL?

Ответы

Ответ 1

Как вы выполнили проверку, требующую ввода чтобы выполнить свою работу без использования анти-шаблона SL?

Я использую FluentValidation.NET для выполнения проверки в моих приложениях. Это позволяет мне вставлять зависимости в мои валидаторы. У этого есть действительно хорошая интеграция с ASP.NET MVC. Он также поддерживает автоматическую проверку на стороне клиента для стандартных правил точно так же, как аннотации данных с использованием jquery unobtrusive validate:

  • NotNull/NotEmpty
  • Матчи (регулярное выражение)
  • InclusiveBetween (диапазон)
  • CreditCard
  • Email
  • EqualTo (сравнение сравнений между свойствами)
  • Длина

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

Ответ 2

Внесите свою валидацию в свою модель.

Атрибуты проверки могут стать неудобными для работы, когда ваши истории проверки становятся более сложными. Тьфу!

Мне нравится использовать Entity Framework с кодом First. В этот момент я полностью контролирую свою модель. Я также использую FluentValidation, например @Darin Dimitrov, и мне очень нравится его простота использования и простой синтаксис.

Вот как вы собрали это. Я предполагаю, что у вас есть сборка с вашими интерфейсами или контрактами.

Это будет базовый интерфейс для ваших моделей...

using System.ComponentModel;
using FluentValidation.Results;

public interface IAbstractBase : IDataErrorInfo
{
    bool IsValid { get; }
    ValidationResult SelfValidate();
}

и его коллега в вашем бизнес-слое выглядит следующим образом:

using System;
using System.Linq;
using FluentValidation.Results;
using Contracts;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public abstract class AbstractBase : IAbstractBase
{
    #region IDataErrorInfo

    public abstract ValidationResult SelfValidate();

    [NotMapped]
    public bool IsValid
    {
        get
        {
            return SelfValidate().IsValid;
        }
    }

    [NotMapped]
    public string Error
    {
        get
        {
            var results = SelfValidate().Errors.Select(s => string.Format("● {0}{1}", s.ErrorMessage, Environment.NewLine)).ToArray();
            return string.Join("", results);
        }
    }

    [NotMapped]
    public IList<ValidationFailure> Errors
    {
        get
        {
            var results = SelfValidate().Errors;
            return results;
        }
    }

    [NotMapped]
    public string this[string columnName]
    {
        get
        {
            var validationResults = SelfValidate();
            if (validationResults == null) return string.Empty;
            var columnResults = validationResults.Errors.FirstOrDefault(x => string.Compare(x.PropertyName, columnName, true) == 0);
            return columnResults != null ? columnResults.ErrorMessage : string.Empty;
        }
    }
    #endregion
}

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

public class MyModel : AbstractBase, IMyModel
{
    private AbstractValidator<IMyModelValidator> _myModelValidator;
    public MyModel():this(new MyModelValidator()){};
    public MyModel(AbstractValidator<IMyModelValidator> myModelValidator){
         _myModelValidator = myModelValidator;
    };

    public int MyModelId { get; set; }
    public string Name { get; set; }
    public DateTime CreatedDate { get; set; }

    public override ValidationResult SelfValidate()
    {
        return _myModelValidator.Validate(this);
    }
}

Ваш класс проверки будет выглядеть примерно так.

 public class MyModelValidator : AbstractValidator<IMyModelValidator>
    {
        private IMyModelProvider _myModelProvider;
        public MyModelValidator(IMyModelProvider myModelProvider){ _myModelProvider = myModelProvider;};
        private void SetRules()
        {
            RuleFor(x => x.Name).NotEmpty().WithMessage("Please specify a project name.");
            RuleFor(x => x.Name.Length).LessThanOrEqualTo(100).WithMessage("The project name must be less than or equal to 100 characters.");
        }

        public override ValidationResult Validate(IMyModel instance)
        {
            SetRules();
            return base.Validate(instance);
        }
    }

Передайте результаты проверки вашей модели в свое представление в своем контроллере, используя следующий вызов в вашем контроллере.

 TryValidateModel(your model here);

После вызова этого в контроллере вызовите свойство model.IsValid.

Удостоверьтесь, что вы регистрируете все, и вам должно быть хорошо идти. Я предполагаю, что вы можете заполнить недостающие части.

Общая картина выглядит так: enter image description here