3

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

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

此 SlackDisplayName 属性是 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; }

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

4

1 回答 1

3

我自己解决了!

首先,您需要以下 Unity Extension 和 Strategy:

信息:在此处找到:UnityContainer.BuildUp() - 只有当这些实例为空时,我才能让它将新实例注入属性?

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

container 是你设置的 IUnityContainer。设置 [DependencyAttribute] 后,您现在应该在 Annotations Instance 中有实例,并且应该调用标有 [InjectionMethod] 的方法。

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

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

于 2013-07-19T19:17:27.363 回答