使用ASP MVC和Castle Windsor将数据库注入到验证属性中

7

我需要一些帮助 - 我正在尝试在一个需要进行数据库调用的ASP.NET MVC Web项目中使用自定义验证属性。

我的控制器已经成功地使用了Windsor,并且IRepository接口也被正常注入。但是当我需要将该仓储注入到属性类中时,问题就出现了。

该属性类的代码如下:

public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute
{
    private readonly string message;
    private readonly IArticleRepository articleRepository;

    public ValidateUniqueUrlNodeAttribute(string message)
    {
        this.message = message;
    }

    public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message)
    {
        this.articleRepository = articleRepository;
    }
    public override IValidator Build()
    {
        var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message };

        ConfigureValidatorMessage(validator);

        return validator;
    }

我的问题是,我似乎无法让Windsor拦截属性的构造函数,以便传递给IArticleRepository。

我的global.asax文件中当前的代码如下:

container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
   container
     .RegisterControllers(Assembly.GetExecutingAssembly())
     .AddComponent<IArticleRepository, ArticleRepository>()
     .AddComponent<ValidateUniqueUrlNodeAttribute>();

任何帮助都将不胜感激。
4个回答

5
据我所知,没有任何依赖注入容器能够直接管理属性,因为它是由运行时实例化的,无法拦截。然而,它们可以通过以下方式“欺骗”:

  1. 使用静态网关到容器 (example),或
  2. 使用“BuildUp”功能,将依赖项注入已构建对象中发现的任何依赖项。这称为Unity中的BuildUp或Autofac中的InjectProperties

Windsor不支持#2 (ref1, ref2),因此您只能:

  1. 尝试使用其中一种hack使Windsor支持#2 (hack1, hack2)
  2. 使用静态网关
  3. 实现自己的IValidatorBuilder并使用Windsor创建验证器。我相信这已经在某个地方实现了,但我现在找不到它...

0

我能够将它连接起来[使用Autofac,但这只是通过ASP.NET MVC的构造函数注入DependencyResolver] 在这个答案中,使得我们可以编写:

class MyModel 
{
    ...
    [Required, StringLength(42)]
    [ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
    public string MyProperty { get; set; }
    ....
}

public class MyDiDependentValidator : Validator<MyModel>
{
    readonly IUnitOfWork _iLoveWrappingStuff;

    public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
    {
        _iLoveWrappingStuff = iLoveWrappingStuff;
    }

    protected override bool IsValid(MyModel instance, object value)
    {
        var attempted = (string)value;
        return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
    }
}

使用一些辅助类(看那里),你可以在 ASP.NET MVC 中像这样在 Global.asax 中进行连接:

DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
    typeof(ValidatorServiceAttribute),
    (metadata, context, attribute) =>
        new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));

0

不知道这是否有所帮助,但我对 ValidationAttribute 进行了子类化,以公开类似于 Resolve<T>() 的方法:

public abstract class IocValidationAttribute : ValidationAttribute
{
    protected T Resolve<T>()
    {
        return IocHelper.Container().Resolve<T>();
    }
}

那么它可以在任何需要访问数据库的自定义ValidatorAttribute中使用:

public class UniqueEmailAttribute : IocValidationAttribute
{
    public override bool IsValid(object value)
    {
        ICustomerRepository customerRepository = Resolve<ICustomerRepository>();

        return customerRepository.FindByEmail(value.ToString()) == null;
    }
}

我认为这是Mauricio Scheffer提到的“静态网关”方法的变体。我不知道这是否是一个好的设计。我不是很喜欢它,我更希望依赖项被注入得更加“优雅”,虽然我显然不能使用构造函数注入,但我想使用属性注入,但无法找到一种方法来钩入ASP.NET MVC框架代码以实现此目的(我甚至已经仔细研究了MVC2源代码)。


你从哪里获取IocHelper? - soniiic
3
@soniiic看起来像一个邪恶的静态。 - Aran Mulholland

-1

嗯。

你能测试一下删除(string message)构造函数的效果,看看这是否至少会强制Castle使用带有Repostiory构造函数的构造函数?

否则我们就调用AddComponent(name,type,type)。除此之外,它应该可以工作......

还有,这是否暗示了我的第一个想法?我如何使用Windsor将依赖项注入到ActionFilterAttributes中


抱歉,我无法删除字符串CTOR,因为属性看起来像这样: [ValidateUniqueUrlNode("请输入唯一的Url")] public string UrlNode { get; set; }这应该不同吗? - David E
嗯,还在纠结中...我得再搜索一下。 - penderi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接