Reputation: 1693
Following on from this discussion, I also have some legacy code that rather than doing DI properly has passed the container around the application, I think this is because of some generic/factory/dynamic code that meant when they did this it was easier for them to pass the container around than rewrite the entire system!
They then simply got what they needed from the container instance when they needed it. i.e.
public class SomeStageInAPipeline :
{
private readonly IBlobAccessClient _blobAccessClient;
public SomeStageInAPipeline (Container container)
{
_blobAccessClient = container.GetInstance<IBlobAccessClient>();
}
This is fine until we have the scenario of instances registered conditionally, i.e.
container.RegisterConditional(typeof(IBlobAccessClient),
Lifestyle.Singleton.CreateRegistration(
() => new BlobAccessClient(srcConnectionString), container),
c => c.Consumer.Target.Parameter.Name.Contains("src"));
container.RegisterConditional(typeof(IBlobAccessClient),
Lifestyle.Singleton.CreateRegistration(
() => new BlobAccessClient(destConnectionString), container),
c => c.Consumer.Target.Parameter.Name.Contains("dest"));
I can set one as the default, i.e.
container.RegisterConditional(typeof(IBlobAccessClient),
Lifestyle.Singleton.CreateRegistration(
() => new BlobAccessClient(srcConnectionString), container),
c => c.Handled == false);
which works fine for the existing requests to GetInstance(<IBlobAccessClient>)
but I've no idea how I would access the other "dest" instance or if it's even possible.
UPDATE What I want to be able to do is:
public class SomeStageInAPipeline :
{
private readonly IBlobAccessClient _srcBlobAccessClient;
private readonly IBlobAccessClient _destBlobAccessClient;
public SomeStageInAPipeline (Container container)
{
_srcBlobAccessClient = container.GetInstance<IBlobAccessClient>();
// obviously the below just gets me the default instance
_destBlobAccessClient = container.GetInstance<IBlobAccessClient>();
}
Upvotes: 1
Views: 896
Reputation: 172826
A registration is conditional based on its context. When you resolve directly from the Container
however, you lose all possible contextual information. The resolved type becomes a new root type. That's one of the many reasons why injecting the Container
directly is a really bad idea.
You could inject inject some sort of Func<string, IBlobAccessClient>
delegate instead, but since you are making changes to SomeStageInAPipeline
already, refactor directly to Constructor Injection as follows:
public class SomeStageInAPipeline
{
private readonly IBlobAccessClient _srcBlobAccessClient;
private readonly IBlobAccessClient _destBlobAccessClient;
public SomeStageInAPipeline(
IBlobAccessClient srcBlobAccessClient,
IBlobAccessClient destBlobAccessClient)
{
_srcBlobAccessClient = srcBlobAccessClient;
_destBlobAccessClient = destBlobAccessClient;
}
}
When you resolve SomeStageInAPipeline
from the Container
, either by calling GetInstance<SomeStageInAPipeline>()
or by injecting it into a consumer, Simple Injector will build up the expected object graph with those conditionals for you.
UPDATE:
If changing the constructor signature of SomeStageInAPipeline
is not possible at this point in time, consider moving the IBlobAccessClient
parameters into a Parameter Object and resolve that parameter object from the Container
:
public sealed class BlobAccessClients
{
public readonly IBlobAccessClient Src;
public readonly IBlobAccessClient Dest;
public BlobAccessClients(IBlobAccessClient src, IBlobAccessClient dest)
{
this.Src = src;
this.Dest = dest;
}
}
This allows you to change the SomeStageInAPipeline
to the following:
public class SomeStageInAPipeline
{
private readonly IBlobAccessClient _srcBlobAccessClient;
private readonly IBlobAccessClient _destBlobAccessClient;
public SomeStageInAPipeline (Container container)
{
var clients = container.GetInstance<BlobAccessClients>();
_srcBlobAccessClient = clients.Src;
_destBlobAccessClient = clients.Dest;
}
}
Upvotes: 2