Setter / property injection in Unity without attributes

后端 未结 8 660
星月不相逢
星月不相逢 2020-12-04 15:58

I am working on a project where the Unity framework is used as the IoC container. My question relates to injecting an optional dependency (in this case a logger) into severa

相关标签:
8条回答
  • 2020-12-04 16:23

    You could try this:

    this code in MyClass

    [InjectionMethod]
    public void Initialize(
                     [Dependency] ILogger logger
    

    and then calling it by:

    unitycontainer.BuildUp<MyClass>(new MyClass());
    

    unity will then call Initialize method with the dependency from the container and then u can save it in a private variable in MyClass or something...

    0 讨论(0)
  • 2020-12-04 16:25

    I am also not a big fan of using attributes but I also don't like the .Configure<InjectedMembers>() method because you're bound to a specific property name and specific value. The way I've found that gives you the most flexibility is to create your own builder strategy.

    I created this simple class that iterates the properties of an object being built up and sets its property values if the type of that property has been registered with the unity container.

    public class PropertyInjectionBuilderStrategy:BuilderStrategy
    {
        private readonly IUnityContainer _unityContainer;
    
        public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer)
        {
            _unityContainer = unityContainer;
        }
    
        public override void PreBuildUp(IBuilderContext context)
        {
            if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices"))
            {
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type);
    
                foreach (PropertyDescriptor property in properties)
                {
                    if(_unityContainer.IsRegistered(property.PropertyType)
                       && property.GetValue(context.Existing) == null)
                    {
                        property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType));
                    }
                }
            }
        }
    }
    

    You register your BuilderStrategy by creating a UnityContainerExtension. Here is an example:

    public class TestAppUnityContainerExtension:UnityContainerExtension
    {
        protected override void Initialize()
        {
            Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization);
        }
    }
    

    That gets registered with the Unity container as such:

    IUnityContainer container = new UnityContainer();
    container.AddNewExtension<TestAppUnityContainerExtension>();
    

    Hope this helps,
    Matthew

    0 讨论(0)
  • 2020-12-04 16:29

    Have a look at the UnityConfiguration project for convention-based configuration. It works pretty well, though i have an issue while looking up multiple implementations using ResolveAll<IType>(). See this Question.

    container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger());
    container.Configure(c => c.Scan(scan =>
                        {
                            scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company")); // Filter out everthing that are not from my assemblies
                            scan.InternalTypes();
                            scan.With<SetAllPropertiesConvention>().OfType<ILogger>();
                        }));
    
    0 讨论(0)
  • 2020-12-04 16:32

    The original example you posted does look very cumbersome, but you can use auto-implemented properties like this to help clean that code up:

    [Dependency]
    public ILogger Logger { get; set; }
    
    0 讨论(0)
  • 2020-12-04 16:32

    With Unity 2.1 this would work as well:

    var container = new UnityContainer()
                .RegisterType<ILogger, Logger>()
                .RegisterType<ISomeInterface, SomeImplementaion>(
                                    new InjectionProperty("Logger", new ResolvedParameter<ILogger>()));
    

    The injected property of SomeImplementaion class is just

    public ILogger Logger { get; set; }
    
    0 讨论(0)
  • 2020-12-04 16:34

    I don't like those attributes also

    You can do all using the Configure method of the unity container:

    First register the type

    unityContainer.RegisterType<MyInterface,MyImpl>(
                         new ContainerControlledLifetimeManager());
    

    If you have multiple constructors you'll have to do this so Unity invokes the parameterless constructor (if none set Unity will go for the fattest one)

    unityContainer.Configure<InjectedMembers>()
                                .ConfigureInjectionFor<MyImpl>(
                                    new InjectionConstructor()); 
    

    Setting property dependency

    unityContainer.Configure<InjectedMembers>()
                        .ConfigureInjectionFor<MyImpl>(
                             new InjectionProperty(
                                 "SomePropertyName",
                                    new ResolvedParameter<MyOtherInterface>()));
    

    Configuring method dependency

    unityContainer.Configure<InjectedMembers>()
                        .ConfigureInjectionFor<MyImpl>(
                            new InjectionMethod(
                                "SomeMethodName",
                                new ResolvedParameter<YetAnotherInterface>()));
    
    0 讨论(0)
提交回复
热议问题