I have 2 storage (Azure) accounts lets call them src and dest and I have controllers that require access to both and I'm trying to work out how to register these 2 singletons conditionally.
This answer gave me some hope but I can't quite work it out, what I want to do is something like (appreciate RegisterSingletonConditional isn't a valid fn):
IBlobAccessClient src = new BlobAccessClient(srcConnectionString);
IBlobAccessClient dest = new BlobAccessClient(destConnectionString);
container.RegisterSingletonConditional<IBlobAccessClient>(
src,
c => c.Consumer.Target.Parameter.Name.Contains("src"));
container.RegisterSingletonConditional<IBlobAccessClient>(
dest,
c => c.Consumer.Target.Parameter.Name.Contains("dest"));
Any guidance appreciated.
There is a non-generic RegisterConditional
overload that accepts a Registration
object. You can wrap your BlobAccessClient
instance in a Registration
and pass it on to RegisterConditional
as shown here:
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"));
If this is a common pattern, you can simplify your code a bit by defining a simple extension method as follows:
public static void RegisterConditionalInstance<TService>(
this Container container, TService instance, Predicate<PredicateContext> predicate)
where TService : class
{
container.RegisterConditional(typeof(TService),
Lifestyle.Singleton.CreateRegistration(() => instance, container),
predicate);
}
This allows you to reduce the previous configuration to the following:
container.RegisterConditionalInstance<IBlobAccessClient>(
new BlobAccessClient(srcConnectionString),
c => c.Consumer.Target.Parameter.Name.Contains("src"));
container.RegisterConditionalInstance<IBlobAccessClient>(
new BlobAccessClient(destConnectionString),
c => c.Consumer.Target.Parameter.Name.Contains("dest"));
Optionally, you can simplify the predicate by extracting this to a simple method as well:
private static Predicate<PredicateContext> InjectedIntoTargetNamed(string targetName) =>
c => c.Consumer.Target.Name.Contains(targetName);
This reduces the registration to the following:
container.RegisterConditionalInstance<IBlobAccessClient>(
new BlobAccessClient(srcConnectionString),
InjectedIntoTargetNamed("src"));
container.RegisterConditionalInstance<IBlobAccessClient>(
new BlobAccessClient(destConnectionString),
InjectedIntoTargetNamed("dest"));
I would suggest defining two new interfaces:
public interface IBlobAccessClientSource : IBlobAccessClient
{ }
public interface IBlobAccessClientDestination : IBlobAccessClient
{ }
And then registering them both individually (in whatever way that SimpleInject supports).
Then in your consumers, inject in IBlobAccessClientSource
and / or IBlobAccessClientDestination
as needed. This will ensure that there are two singleton registrations - one for each of the two interfaces.