如何在.NET MVC3中注入用于验证的依赖项?

时间:2012-01-11 11:52:16

标签: asp.net-mvc-3 validation dependency-injection

我们有很多验证方法需要访问存储库/数据库才能完成工作。到目前为止,我们一直在使用服务定位器模式(尽管很少)在自定义ValidationAttributes中实现这一点:

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

我知道这是:(作为反模式,我们想使用更正确的方法。我们使用统一,我读this post that says to use a build-up method。但是the link in the accepted answer说文档已过时(退休内容)。

解决方案不需要使用验证属性,我想它可以使用IValidatableObject,但问题仍然存在:如何将依赖项注入模型。我们需要一个自定义模型绑定器吗?

另一个解决方案是在控制器中执行验证,其中依赖注入很容易。对我来说,这感觉很混乱。我希望模型在到达action方法时得到验证。

此外,我们有时会使用[RemoteAttribute]在客户端上执行某些验证。目前,这些方法通过使用静态Validator.TryValidateObject方法构造视图模型并将验证委托给模型。

如何在不使用SL反模式的情况下完成需要注入依赖项才能完成工作的验证?

2 个答案:

答案 0 :(得分:12)

  

您是如何完成需要注入的验证的?   依赖于完成其工作,而不使用SL反模式?

我使用FluentValidation.NET在我的应用程序中执行验证。它允许我inject dependencies进入我的验证器。它有一个非常好的integration with ASP.NET MVC。它还支持标准规则的自动客户端验证,就像使用jquery unobtrusive验证的数据注释一样:

  • NOTNULL / NotEmpty
  • 匹配(正则表达式)
  • InclusiveBetween(range)
  • 信用卡式
  • 电子邮件
  • EqualTo(跨财产平等比较)
  • 长度

我从未使用过数据注释来执行验证。当您需要处理更多复杂验证方案时,它们绝对无用,您需要验证依赖属性甚至使用某些服务。我在前一句中用斜体字表示复杂,因为我不认为validating that one of the 2 properties是一个非常复杂的验证方案,但是,只需检查一下你必须编写的基础设施废弃量,以便使用它来实现它数据注释。看看这段代码,你不再知道你在验证什么。

答案 1 :(得分:1)

将验证注入模型。

当您的验证故事变得更加复杂时,验证属性可能会变得很难处理。呸!

我喜欢将Codeity框架与Code First一起使用。那时我完全控制了我的模型。我也像@Darin Dimitrov一样使用FluentValidation,我非常喜欢它的易用性和简单的语法。

这是你如何把它放在一起。 我假设你有你的接口或合同的汇编。

这将是您的模型的基础界面......

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);
        }
    }

使用控制器中的以下调用将模型中的验证结果传递到Controller中的视图。

 TryValidateModel(your model here);

在控制器中调用此函数后,请调用model.IsValid属性。

确保你注册了一切,你应该好好去。我假设你可以填写缺失的部分。

大局看起来像这样: enter image description here