使用Unity';s在(数据)注释中的依赖项注入

本文关键字:注释 依赖 注入 数据 Unity 使用 | 更新日期: 2023-09-27 18:23:44

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

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

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

  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 Container:中获取ICultureContext

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

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

使用Unity';s在(数据)注释中的依赖项注入

我自己解决了!

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

信息:在这里找到:UnityContainer.BuildUp()-只有当属性为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实例中有实例,并且应该调用用[InpjectionMethod]标记的方法。

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

如果你有类似的问题,希望你能使用这个;)