I got an example where I want to use DI to create instances of a class in a foreach loop but cannot figure which lifetime manager to use. The default lifetime manager will obviously only use the instance injected in the controller where I want to create new instances each time the instance is called as illustrated in the example below. I'm using Microsoft Unity
Simple interface class
public interface ISomeClass
{
string GetValue(string value);
}
public class SomeClass : ISomeClass
{
public string GetValue(string value)
{
return value;
}
}
Register in container
container.RegisterType<ISomeClass, SomeClass>(new TransientLifetimeManager());
Implementation
private readonly SomeClass _someClass;
public MyController(SomeClass someClass)
{
_someClass = someClass;
}
// someStringList would contain values like "hello", "world", "o", "hai"
public void Whatever(List<string> someStringList)
{
List<string> otherStringList = new List<string>();
foreach (var someString in someStringList)
{
// _someClass.GetValue will simply return the same value
otherStringList.Add(_someClass.GetValue(someString));
}
// otherStringList contain as many elements as the someStringList
// but all will be the same as the last element in the list
}
The TransientLifetimeManager
lifetime manager is the way to go. That one will create new object each time you, or container itself, call Resolve
.
So the point is to initiate that Resolve
somehow within the foreach
. The naive\simple approach could be to inject IUnityContainer
itself into your controller, the IUnitContainer
itself is always available...
private readonly IUnityContainer _container;
public MyController(IUnityContainer container)
{
_container = container;
}
then resolve ISomeClass
manually:
foreach (var someString in someStringList)
{
var someClass = _container.Resolve<ISomeClass>();
otherStringList.Add(_someClass.GetValue(someString));
}
Generally, I would prefer more some kind of factory or prototype pattern instead of injecting the IUnityContainer
itself as that might be considered as a bad practice. The container should be used more as an invisible helper instead of first class citizen...
The easy factory approach can be to register the simple factory method:
_container.RegisterType<Func<ISomeClass>>(new InjectionFactory(_ =>
new Func<ISomeClass> (() => _container.Resolve<ISomeClass>())));
then you can inject this into your controller:
private readonly Func<ISomeClass> _factory;
public MyController(Func<ISomeClass> factory)
{
_factory = factory;
}
and then you it as:
foreach (var someString in someStringList)
{
ISomeClass someClass = _factory();
otherStringList.Add(_someClass.GetValue(someString));
}
The good thing about the second approach is that you have explicit dependency instead of injecting IoC, which makes your design cleaner.