2013-07-18 72 views
3

我使用的統一,並有標記數據註釋的型號:在(數據)註釋使用Unity的依賴注入

public class SomeModel 
{  
    [SlackDisplayName("ED0CAD76-263E-496F-ABB1-A4DFE6DEC5C2")] 
    public String SomeProperty { get; set; }  
} 

這SlackDisplayName屬性是一個子類顯示名稱,它解決了一個靜態的顯示名稱爲屬性。我只是想通過滿足這個標準來動態制定這個標準:

  1. 使用這個註解是可能的。
  2. 我可以使用該註釋實現多語言應用程序。
  3. 語言模板得到由GUID標識
  4. 我不得通過文化id來註釋

所以此外,我SlackDisplayName註釋是這樣的:

/// <summary> 
/// Annotation for non-fixed display names 
/// </summary> 
public class SlackDisplayNameAttribute : DisplayNameAttribute 
{ 
    /// <summary> 
    /// TODO 
    /// </summary> 
    /// <param name="identifierGUID"></param> 
    public SlackDisplayNameAttribute(String identifierGUID) 
     : this(Guid.Parse(identifierGUID)) 
    { 
    } 

    /// <summary> 
    /// TODO 
    /// </summary> 
    /// <param name="identifier"></param> 
    public SlackDisplayNameAttribute(Guid identifier) 
     : base() 
    { 

    } 

    /// <summary> 
    /// The culture context to use. 
    /// </summary> 
    [Dependency] 
    public ICultureContext Context { get; set; } 

    /// <summary> 
    /// Gets the display name for the given GUID. 
    /// </summary> 
    public override string DisplayName 
    { 
     get 
     { 
      return "NOT_DEFINED"; 
      //return Context.GetLanguageTemplate(new Guid()); 
     } 
    } 
} 

現在的問題是:如何從我的Unity容器中獲取ICultureContext:

[Dependency] 
public ICultureContext Context { get; set; } 

它已經註冊,但我不知道如何獲得該屬性注入。

回答

3

我自己解決了!

首先,您需要滿足以下統一推廣和戰略:

信息:這裏找到:UnityContainer.BuildUp() - Can I make it inject new instances into properties only if these are null?

public class RecursiveBuildUpContainerExtension : UnityContainerExtension { 
    protected override void Initialize(){ 
     Context.Strategies.Add(new RecursiveBuildUpBuilderStrategy(Context.Container), UnityBuildStage.PreCreation); 
    } 
} 

public class RecursiveBuildUpBuilderStrategy : BuilderStrategy { 
    readonly IUnityContainer container; 
    public RecursiveBuildUpBuilderStrategy(IUnityContainer container) { 
     this.container = container; 
    } 

    public override void PreBuildUp(IBuilderContext context) { 

     if(context.Existing == null) return; 

     foreach(var prop in context.Existing.GetType().GetProperties()) { 

      if(ContainsType<DependencyAttribute>(prop.GetCustomAttributes(true))) { 

       if(prop.GetValue(context.Existing, null) == null) { 
        var value = container.Resolve(prop.PropertyType); 
        prop.GetSetMethod().Invoke(context.Existing, new[] { value }); 
       } 
       else { 
        var value = container.BuildUp(prop.PropertyType, prop.GetValue(context.Existing, null)); 
        prop.GetSetMethod().Invoke(context.Existing, new[] { value }); 
       } 
      } 
     } 

     foreach (var method in context.Existing.GetType().GetMethods()){ 
      if(ContainsType<InjectionMethodAttribute>(method.GetCustomAttributes(true))){ 
       var argsInfo = method.GetParameters(); 
       var args = new object[argsInfo.Length]; 

       for(int i = 0; i < argsInfo.Length; i++) { 
        args[i] = container.Resolve(argsInfo[i].ParameterType); 
       } 

       method.Invoke(context.Existing, args); 
      } 
     } 

     context.BuildComplete = true; 
    } 

    private static bool ContainsType<T>(IEnumerable<object> objects){ 
     foreach (var o in objects){ 
      if(o is T) return true; 
     } 
     return false; 
    } 

} 

你需要這個,因爲它是負責對「注射性建立」。接下來這一點,你需要註冊你的擴展

container.AddNewExtension<RecursiveBuildUpContainerExtension>(); 

此外,你需要重寫默認DataAnnotationsModelMetadataProvider,因爲默認ModelMetaDataProvider不使用統一注入性質的註釋。要做到這一點,實現這個類:

public class DynamicModelMetadataProvider : DataAnnotationsModelMetadataProvider 
{ 
    private IUnityContainer _context; 

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) 
    {   
     foreach (Attribute attribute in attributes) 
      _context.BuildUp(attribute); 

     return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 
    } 

    public DynamicModelMetadataProvider(IUnityContainer context) 
     : base() 
    { 
     this._context = context; 
    } 
} 

之後,編輯你的引導程序,並設置新ModelMetadataProvider,要清楚的MVC框架,它有使用它:

ModelMetadataProviders.Current = new DynamicModelMetadataProvider(container); 

在哪裏容器是你設置的IUnityContainer。當設置[DependencyAttribute]並且用[InjectionMethod]標記的方法應該被調用時,您現在應該在註釋實例中擁有實例。

[Dependency] 
public ICultureContext Context { get; set; } 

希望你可以使用這個,如果你有類似的問題;)

+1

的AddNewExtension接受一個參數,它應該我RecursiveBuilUpContainerExtension。您是否有策略來單元測試使用此數據註釋屬性的類,因爲據我所知,您現在依賴於Mvc並從IoC到單元測試。 –

+0

@PatrickDesjardins,我剛剛明白了,可以看到你的觀點。你有沒有發現在我們的單元測試中不需要使用IoC容器的解決方案? –