2012-10-01 111 views
3

我不能夠執行財產注入的自定義數據註釋驗證屬性Autofac財產注入System.ComponentModel.DataAnnotations ValidationAttribute

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篩選器屬性,但不適用於數據註釋屬性。

任何幫助真的讚賞替代方法,使這項工作。

+0

相關:http://stackoverflow.com/questions/5218333/asp-net-mvc3-set-custom-iserviceprovider-in-validationcontext-so-validators-can –

+0

(對於其他讀者,我敢肯定你知道這一點)在編譯時「,將屬性序列化爲[有效]表示Assembly中二進制屬性和ctor參數的blob。在運行時,Reflection API會將這些內容挖出來,並通過執行大量定製的魔術來交付一個初始版本。通過'new'實例化是完全不同的事情。這裏的關鍵問題當然是沒有Autofac庫對事件進行事後注入,因此您嘗試的任何機制都不會執行任何操作。這留下了兩個途徑 - 「ValidationContext」和服務位置... –

+0

相關:http://stackoverflow.com/questions/986019/database-injection-into-a-validation-attribute-with-asp-mvc-and-castle -windsor –

回答

2

你在分析中是正確的 - Autofac有一個機制可以注入到過濾屬性中[通過不實例化它們作爲屬性,並且依靠設備公開的MVC 3]來實現。

沒有適用於驗證屬性的自然擴展點,Autofac也沒有做任何嘗試。

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在驗證的依賴一定的性能問題(喔,具有諷刺意味的,依賴注入容器)。

任何想法或更好的方法都很受歡迎。

+0

另請參閱http://stackoverflow.com/a/5222249/11635 –

+0

大多數容器都有一個「Inject Into」操作,它有效地完成了上述操作(參見'ILifetimeScope.InjectProperties'),但它確實使它「只是工作「並且服務地點在消費點不是公然的,所以+1 –

2

作爲參考,我們遇到了一個ValidationAttribute問題,它需要使用Repository進行一些數據庫工作,而後者又使用了Entity Framework DbContext。

我們的問題是DbContext被該屬性緩存。這導致它包含的數據過時,影響了驗證結果!

我們固定它做我們的倉庫決心的Autofac Lifetimescope聲明中的IsValid的方法中:

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 
} 

這裏只是將我的解決辦法,因爲我還沒有找到這個解決方案記錄針對此問題其他地方 - 也許它只是其他人那麼明顯沒有人一直是我一樣傻乎乎的:)

0

我解決它有點不同的this answer(您是通過ValidationAttribute仍然佈線的東西),使一個寫:

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