Как внедрить зависимости, используемые для проверки в .NET MVC3? - PullRequest
15 голосов
/ 11 января 2012

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

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

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

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

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

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

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

Ответы [ 2 ]

12 голосов
/ 19 января 2012

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

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

  • NotNull / NotEmpty
  • Совпадения (регулярное выражение)
  • включительно между (диапазон)
  • CreditCard
  • E-mail
  • EqualTo (сравнение равенства между свойствами)
  • Длина

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

1 голос
/ 20 января 2012

Введите вашу проверку в вашу модель.

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

Мне нравится использовать Entity Framework с Code 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

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