在(数据)注释中使用Unity的依赖注入

时间:2013-07-18 16:07:55

标签: c# asp.net-mvc unity-container

我正在使用Unity,并且有一个标有数据注释的模型:

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

此SlackDisplayName属性是DisplayName的子类,它解析属性的静态显示名称。我只是想通过满足这个标准来动态地做到这一点:

  1. 可以使用此注释。
  2. 我可以使用该注释实现多语言应用程序。
  3. 语言模板由GUID标识
  4. 我不能将文化ID传递给注释
  5. 因此,我的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; }
    

    它已注册,但我不知道如何注入该属性。

1 个答案:

答案 0 :(得分:3)

我自己解决了!

首先,您需要以下Unity扩展和策略:

信息:点击此处: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;
    }

}

你需要这个,因为它负责在“BuildUp”上注入属性。在此旁边,您需要注册您的扩展程序

container.AddNewExtension<RecursiveBuildUpContainerExtension>();

此外,您需要覆盖默认的DataAnnotationsModelMetadataProvider,因为默认的ModelMetaDataProvider不使用Unity将属性注入注释。为此,请实现此类:

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]时在Annotations Instance中拥有实例,并且应该调用标有[InjectionMethod]的方法。

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

如果您遇到类似的问题,希望您可以使用此功能;)