物业注入与内部二传手

Fra*_*att 3 properties internal autofac

我有一个现有的应用程序,我正在修改以使用Autofac Property Injection.似乎无论我使用哪种方法来注册具有属性的类型,除非它们具有公共setter,否则属性始终为null.使用其他IoC容器(例如Structuremap),可以将setter设置为内部范围,并使用InternalsVisibleTo程序集中的属性使其可用.限制客户端修改赋值似乎很好.

Autofac可以实现吗?或者在处理属性注入时是否有另一种方法来保证分配安全?

我尝试过使用反射PropertiesAutoWired()以及.WithParameter()从我的WebApi Global.asax中解析- 指定要设置的特定参数,但没有成功作为内部setter.

[assembly: InternalsVisibleTo("MyWebAPI.dll")]
[assembly: InternalsVisibleTo("Autofac.dll")]
[assembly: InternalsVisibleTo("Autofac.Configuration.dll")]
namespace My.Namespace
{
    public class BaseContext
    {
        public MyPublicClass _dbHelper { get; internal set; }

        public BaseContext()
        {

        }

        protected string DbConnectionString
        {
            get
            {
                return _dbHelper.DbConn; //<-Always null unless setter is public
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

nem*_*esv 5

您不能internal使用autofac 注入setter,因为AutowiringPropertyInjector该类只查找公共属性(请参阅source).

但是,这里的逻辑AutowiringPropertyInjector非常简单,因此您可以创建自己的版本,为非公共属性注入:

public static class AutowiringNonPublicPropertyInjector
{
     public static void InjectProperties(IComponentContext context, 
            object instance, bool overrideSetValues)
     {
          if (context == null)
              throw new ArgumentNullException("context");
          if (instance == null)
              throw new ArgumentNullException("instance");
          foreach (
             PropertyInfo propertyInfo in 
                 //BindingFlags.NonPublic flag added for non public properties
                 instance.GetType().GetProperties(BindingFlags.Instance |
                                                  BindingFlags.Public |
                                                  BindingFlags.NonPublic))
         {
             Type propertyType = propertyInfo.PropertyType;
             if ((!propertyType.IsValueType || propertyType.IsEnum) &&
                 (propertyInfo.GetIndexParameters().Length == 0 &&
                     context.IsRegistered(propertyType)))
             {
                 //Changed to GetAccessors(true) to return non public accessors
                 MethodInfo[] accessors = propertyInfo.GetAccessors(true);
                 if ((accessors.Length != 1 || 
                     !(accessors[0].ReturnType != typeof (void))) &&
                      (overrideSetValues || accessors.Length != 2 ||
                      propertyInfo.GetValue(instance, null) == null))
                 {
                     object obj = context.Resolve(propertyType);
                     propertyInfo.SetValue(instance, obj, null);
                 }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以在OnActivated活动中使用这个类了

var builder = new ContainerBuilder();
builder.RegisterType<MyPublicClass>();
builder.RegisterType<BaseContext>()
    .OnActivated(args =>   
          AutowiringNonPublicPropertyInjector
              .InjectProperties(args.Context, args.Instance, true));
Run Code Online (Sandbox Code Playgroud)

但是,上面列出的解决方案现在注入所有类型的属性,所以即使是私有属性和受保护的属性也是如此,因此您可能需要通过一些额外的检查来扩展它,以确保您只注入您期望的属性.