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
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...
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
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>();
}));
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; }
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; }
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>()));