3

我无法对自定义数据注释验证属性执行属性注入

 public class CustomValidationAttribute : ValidationAttribute 
 {
    public ILogger Logger { get; set; }

    public CustomValidationAttribute(string keyPointer)
    { }

    public override bool IsValid(object value)
    {
        // Implementation here
        return true;
    }
}

现在,在我的 MVC Application_Start 方法中,我有以下 Autofac 配置:

        // Autofac Ioc Container
        var builder = new ContainerBuilder();
        builder.RegisterType<Logger>().As<ILogger>().InstancePerHttpRequest();
        builder.RegisterType<CustomValidationAttribute>()
        .OnActivating(e =>
        {
            e.Instance.Logger = e.Context.Resolve<ILogger>();
        });
        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

我还尝试了自动装配功能:

builder.RegisterType<CustomValidationAttribute>().PropertiesAutowired();

我猜数据注释上的属性的属性在编译时被解析并且不受运行时注入的影响。此方法适用于 MVC 过滤器属性,但不适用于数据注释属性。

任何帮助都非常感谢您使用替代方法来完成这项工作。

4

4 回答 4

2

作为参考,我们遇到了 ValidationAttribute 的问题,它需要使用 Repository 进行一些数据库工作,而 Repository 又使用了 Entity Framework DbContext。

我们的问题是 DbContext 被属性缓存了。这导致它包含的数据过时,从而影响了验证的结果!

我们通过在 IsValid 方法内的 Autofac Lifetimescope 声明中执行我们的 Repository 解析来修复它:

using Autofac;

...

public override bool IsValid(object value)
{
    using (var lifetimeScope = MvcApplication.Container.BeginLifetimeScope())
    {
        var repo = lifetimeScope.Resolve<IMyRepo>();

        // Do your validation checks which require the repo here

    } // The repo will be released / disposed here
}

只需在此处添加我的解决方案,因为我在其他任何地方都没有找到针对此问题的解决方案 - 也许很明显没有其他人像我一样愚蠢:)

于 2013-07-30T10:26:48.023 回答
2

您的分析是正确的- Autofac 具有注入过滤器属性的机制[这是通过不将它们实例化为属性并依赖于暴露 MVC 3 的设施来实现的]。

没有适用于验证属性的自然扩展点,Autofac 也没有尝试这样做。

于 2012-10-01T04:02:45.023 回答
1

我最终使用了一个新的验证器和一些反射来设置数据注释中的属性实例。

 public class IocValidator : DataAnnotationsModelValidator<ValidationAttribute>
{
    public IocValidator(ModelMetadata metadata, ControllerContext context,
        ValidationAttribute attribute)
        : base(metadata, context, attribute) { }

    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
        IEnumerable<PropertyInfo> props = 
            from p in Attribute.GetType().GetProperties()
            where p.CanRead 
                && p.CanWrite
                && (p.PropertyType.IsInterface || p.PropertyType.IsAbstract)
            select p;

        foreach (PropertyInfo prop in props)
        {
            var instance = IocHelper.Resolver.GetService(prop.PropertyType);

            if (instance != null)
                prop.SetValue(Attribute, instance, null);
        }

        return base.Validate(container);
    }
}

然后在我的Application_Start我注册了我的新验证器适配器:-

 DataAnnotationsModelValidatorProvider.RegisterDefaultAdapter(typeof(IocValidator));

这种方法和验证器中 IocHelper 的依赖性(哦,讽刺的是,对依赖注入容器的依赖性)有明确的性能影响。

任何想法或更好的方法都非常受欢迎。

于 2012-10-02T15:19:16.813 回答
0

我在这个答案中以不同的方式解决了它(你仍然通过ValidationAttributes 连接东西),使一个人可以写:

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));
于 2016-02-05T10:09:55.843 回答