Unity select a different injection factory - c#

I would like to register two different Injection factories for the same type, for example, it could be the two registrations below.
container.RegisterType<BaseSearchProvider>(
new HierarchicalLifetimeManager(),
new InjectionFactory(c =>ExamineManager.Instance.SearchProviderCollection["Setting 1"]));
container.RegisterType<BaseSearchProvider>(
new HierarchicalLifetimeManager(),
new InjectionFactory(c => ExamineManager.Instance.SearchProviderCollection["Setting 2"]));
For now, foreach type I register manually my constructions. I have different services, but some services need to use the first registration and others the second registration? Is there any way to perform this, by using some "Profile" like this?
container.RegisterType<IMeetingSearchService>("using Setting 1")
The only thing I can think off for now as the solution is to inherit the BaseSearchProvider and to register this type so that I can register two different types and adapt all my constructors with this, so I even don't need that selector. But maybe there is another way?

There is a way to resolve by name.
So you need two different derived types of BaseSearchProvider. Lets call them:
SettingsOneSearchProvider & SettingsTwoSearchProvider
Now we can get get the right settings by using the 'ExamineManager.Instance.SearchProviderCollection["settingsname"]' code in the constructor of the two new providers.
In you registration class you add names to the registrations like this:
container.RegisterType<BaseSearchProvider, SettingsOneSearchProvider>("SettingsOne"
new HierarchicalLifetimeManager(),
new InjectionFactory(c =>ExamineManager.Instance.SearchProviderCollection["Setting 1"]));
container.RegisterType<BaseSearchProvider, SettingsTwoSearchProvider>("SettingsOne"
new HierarchicalLifetimeManager(),
new InjectionFactory(c => ExamineManager.Instance.SearchProviderCollection["Setting 2"]));
Now we need an extra resolve method in the registration class to resolve by name:
public static T Resolve<T>(string name)
{
return container.Resolve<T>(name);
}
Now you can resolve one of the two by using this code:
var provider = RegistationClassName.Resolve<BaseSearchProvider>("SettingsOne");

Related

C# Dependency Injection In Constructor with a parameter at runtime

Perhaps I am missing something or tried something improperly, but I thought I would reach out.
I have a singleton service that I want to create multiple times. The service has the same logic except for a configuration parameter. So I want to inject a parameter at runtime into the service constructor.
Is this possible, or will I have to do something more elaborate?
Thanks for your input.
For example…
// I am creating three different configurations
services.Configure<ProfileCacheOptions>(
ProfileCacheOptions.Key1,
config.GetSection(ProfileCacheOptions.Key1));
services.Configure<ProfileCacheOptions>(
ProfileCacheOptions.Key2,
config.GetSection(ProfileCacheOptions.Key2));
services.Configure<ProfileCacheOptions>(
ProfileCacheOptions.Key2,
config.GetSection(ProfileCacheOptions.Key3));
.
.
.
// I have tried multiple ways to inject a parameter, but as you can see
// my last attempt was a simple string representing the key
services.AddSingleton<ICachedDataSource<Class1>,
MemoryCacheData<Class1>>(ProfileCacheOptions.Key1);
services.AddSingleton<ICachedDataSource<Class2>,
MemoryCacheData<Class2>>(ProfileCacheOptions.Key2);
services.AddSingleton<ICachedDataSource<Class3>,
MemoryCacheData<Class3>>(ProfileCacheOptions.Key3);
// The proposed argument, whatever it may be
public MemoryCacheData(
IMemoryCache cache,
IOptionsSnapshot<CachedDataBaseClassOptions> options,
string TheArgument
{
_options = options.Get(TheArgument);
}
I have tried creating an argument class and multiple attempts to create a runtime injected parameter.
You can create an instance of the singleton before you add it to the DI container, like so:
var singleton1 = new MemoryCacheData<Class1>(ProfileCacheOptions.Key1);
services.AddSingleton(typeof(ICachedDataSource<Class1>), singleton1);
You have to provide a factory (or in this case a simple Func<>) that creates the desired instance at runtime. Something like this:
services.AddSingleton<ICachedDataSource<Class1>>(provider =>
{
// The provider is the running DI container and you can ask
// for any service as usual to retrieve dependencies
var cacheOptions = provider.GetRequiredService<ICachedDataSource<Class1>>();
var data = new MemoryCacheData<Class1>(cacheOptions);
return data;
});
I think it doesn't fully match your code, but hopefully you understand the approach and can use it.

Structure map - understanding Use and Add semantics

I have the following code with NServiceBus & StructureMap 2.6.2 wired up together:
var bus = Configure.WithWeb().StructureMapBuilder(container)
ObjectFactory.Container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
container.Configure(r => r.For<IBus>().Singleton().Add<MyBus>().Named("named"));
I want first registration to be a default one, second registration to be available as a named one. But when I run:
var bus1 = container.GetInstance<IBus>();
var bus2 = container.GetInstance<IBus>("named");
I get both instances of type MyBus. According to this question first instance must come from first registration (of type UnicastBus) but it is not.
Am I understanding Use and Add semantics wrong?
You are registering the first instance in the ObjectFactory container instance. The second instance is being registered in a local container instance named container.
For this behavior to work right, you need to use the same container instance for both registrations.
On a side note, you should never use the ObjectFactory static instance (as per the documentation).
The static ObjectFactory wrapper for Container is still available in 3.0, but we strongly recommend against using it for new applications. It only exists for easier compatibility with older installations.
Both registrations:
ObjectFactory.Container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
and
container.Configure(r => r.For<IBus>().Singleton().Add<MyBus>().Named("named"));
are applied do different instances of container (container != ObjectFactory.Container). This results in container having only one registration of IBus (MyBus) and that is why you can only resolve this dependency. When you register only one type (even if it is named instance) for specific plugin type you are able to resolve it when using container.GetInstance<TPluginType>(). To fix this issue and have expected behavior you need to change this registration:
ObjectFactory.Container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
with this:
container.Configure(r =>
r.For<IBus>().Singleton().Use(Configure.Instance.CreateBus().Start())
);
Tested this issue in both versions of SM (2.6 and 3+) and the behavior is the same on these versions.
Hope this helps!

Adding interception on existing registration

In this scenario I my application is handed an already initialized UnityContainer on which has been registered a type which boils down to this:
container.RegisterType<IService>(new InjectionFactory(c => new Service()));
What I need to achieve is adding an interceptor ServiceInterceptor to the IService registration. I suppose the obvious answer is: Do this by running a second RegisterType<IService> and applying the interceptor as injection members. However, re-creating the provided injection factory and delegate as described below is unfortunately not feasible. The new Service() statement isn't available to me at this point.
container.RegisterType<IService>(
new InjectionFactory(c => new Service()),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<ServiceInterceptor>());
So: I am looking for a way to add further injection members to an existing ContainerRegistration.
// 1. Get the current container registration
var containerRegistration = container.Registrations
.First(cr => cr.RegisteredType == typeof(IService));
// 2. Is this even possible?
ApplyInterception(
containerRegistration,
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<ServiceInterceptor>());
// 3. Profit!
You could initially register the type as a named registration (using the InjectionFactory) while also providing a default registration (with no name) that just resolves the named registration:
container.RegisterType<IService>("original",
new InjectionFactory(c => new Service()));
container.RegisterType<IService>(
new InjectionFactory(c => c.Resolve<IService>("original")));
So you can resolve IService as you would normally do. However you will now be able to replace the default registration while keeping the original named registration. This way you can work around your issue, where you couldn't re-register IService due to the factory statement not being available at that point.
With this approach in place, at a later point you can override the default IService registration with one where interception is registered and still uses the original named registration for resolving the instance:
container.RegisterType<IService>(
new InjectionFactory(c => c.Resolve<IService>("original")),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<ServiceInterceptor>());
If you now resolve IService, you will still use the original factory method c => new Service() as it is resolving the "original" named registration, but this time your ServiceInterceptor is also applied.
I have created this fiddle so you can check a full working example.
There is a second approach using Policy Injection. (See Policy Injection section in the msdn).
First configure your type as usual, but leave the door opened for using Policy Injection:
container.RegisterType<IService>(
new InjectionFactory(c => new Service()),
new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<InterfaceInterceptor>());
At this point your service is registered without any interception being applied. However at a later point you can add a policy injection rule, for example matching your service type name, that adds the interception:
container.Configure<Interception>()
.AddPolicy("yourInterceptor")
.AddMatchingRule<TypeMatchingRule>
(new InjectionConstructor("MyNamespace.Service", true))
.AddCallHandler<ServiceInterceptorHandler>(
new ContainerControlledLifetimeManager(),
new InjectionConstructor(),
new InjectionProperty("Order", 1));
Now if you resolve IService, the interception logic in ServiceInterceptorHandler will be applied (This class is basically the same as ServiceInterceptor in the first approach, but implementing ICallHandler instead of IInterceptionBehavior)
Again, check the example in this fiddle
Having a look at both options, I personally feel more comfortable with the first approach, avoiding the overhead of the matching rules.
The first approach would also allow you to easily completely turn off interception by overriding again the IService registration, saving you from the interceptors overhead if you want it completely off. (Both approaches allow you to implement the WillExecute property of the interceptor/handler classes, but you still have the overhead of the interceptors). You can do this using policy injection, but you need another intermediate call handler, see this post
However with the second approach, you could apply this solution to multiple classes using the matching rules (For example all classes in a namespace, or all classes whose name follows a specific pattern, etc. You can take a look at the matching rules here)
In the end you will need to decide which one fits you best. (and there might be other approaches, would love to see them posted!)

Register same implementation for multiple interfaces

I have a class that implements a number of interfaces
public class AwesomeThingClass: IAwesome<Thing>, IAwesomeThing {
// parameterized constructor, so can't use RegisterAutowiredAs
public AwesomeThingClass(IClient client, string connectionString) {}
}
It encapsulates multithreading operations with limited cardinality (I mean, only N of such operations are allowed to run simultaneously) by using semaphores.
However, if I register it with IoC using something like
container.Register<IAwesome<Thing>>(cont => new AwesomeThingClass(cont.Resolve<IClient>(), connStr))
container.Register<IAwesomeThing>(cont => new AwesomeThingClass(cont.Resolve<IClient>(), connStr))
I end up with two instances that could be resolved using IAwesome<Thing> and IAwesomeThing, which allows to run 2*N operations. I definitely need same instance resolved for both interfaces. Are there any way to achieve this, except for manually instantiating class and registering instance?
This question is essentially similar to Register the same type to multiple interfaces, but it's not it's duplicate, as I'm using ServiceStack IoC container (Func at the time of writing), while that question is about Unity
There might be a simple solution specialized for ServiceStack IoC but you could also use a Lazy<T> to return the same value from both of your lambdas.
var lazy = new Lazy<AwesomeThingClass>(() =>
new AwesomeThingClass(container.Resolve<IClient>(), connStr));
container.Register<IAwesome<Thing>>(cont => lazy.Value);
container.Register<IAwesomeThing>(cont => lazy.Value);
(I'm assuming that the cont parameter of the lambda would be the same object as the container variable.)
You should be able to just cast it:
container.Register<IAwesomeThing>(c =>
new AwesomeThingClass(c.Resolve<IClient>(), connStr));
container.Register(c => (IAwesome<Thing>) c.Resolve<IAwesomeThing>()));

Can I pass constructor parameters to Unity's Resolve() method?

I am using Microsoft's Unity for dependency injection and I want to do something like this:
IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context
IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);
RepositoryA and RepositoryB both have a constructor that takes an IDataContext parameter, and I want Unity to initialize the repository with the context that I pass it. Also note that IDataContext is not registered with Unity (I don't want 3 instances of IDataContext).
As of today they have added this functionality:
It’s in the latest drop here:
http://unity.codeplex.com/SourceControl/changeset/view/33899
Discussion on it here:
http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434
Example:
container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
< 2 cents>
What if you later on decide to use a different service that requires more or less than just the context?
The problem with constructor parameters and IoC is that the parameters are ultimately tied to the concrete type being used, as opposed to being part of the contract that the service interface defines.
My suggestion would be that you either resolve the context as well, and I believe Unity should have a way for you to avoid constructing 3 instances of it, or you should consider a factory service that has a way for you to construct the object.
For instance, what if you later on decide to construct a repository that doesn't rely on a traditional database at all, but instead use an XML file to produce dummy-data for the test? How would you go about feeding the XML content to that constructor?
IoC is based around decoupling code, by tying in the type and semantics of the arguments to the concrete types, you really haven't done the decoupling correctly, there's still a dependency.
"This code can talk to any type of repository possibly, as long as it implements this interface.... Oh, and uses a data context".
Now, I know that other IoC containers have support for this, and I had it in my first version of my own as well, but in my opinion, it doesn't belong with the resolution step.
< /2 cents>
Thanks guys ... mine is similar to the post by "Exist". See below:
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();
_activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
{
new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
});
You can use InjectionConstructor / InjectionProperty / InjectionMethod depending on your Injection Architecture within the ResolvedParameter< T >("name") to get a instance of a pre-registered Object in the container.
In your case this Object must be registered with a Name, and for the same insance you need ContainerControlledLifeTimeManager() as the LifeTimeManager.
_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");
var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));
The very short answer is: no. Unity currently has no way to pass parameters into the constructor that aren't constant or injected, that I have been able to find. IMHO that's the single biggest thing it's missing, but I think it is by design rather than by omission.
As Jeff Fritz notes, you could in theory create a custom lifetime manager that knows which context instance to inject into various types, but that's a level of hard-coding which seems to obviate the purpose of using Unity or DI in the first place.
You could take a small step back from full DI and make your repository implementations responsible for establishing their own data contexts. The context instance can still be resolved from the container but the logic for deciding which one to use would have to go into the implementation of the repository. It's not as pure, certainly, but it would get rid of the problem.
Another alternative you could use (don't really know if it is a good practice or not) is creating two containers and registering an instance for each:
IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context
//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance
hope this helps too
NotDan, I think you may have answered your own question in comments to lassevk.
First, I would use a LifetimeManager to manage the lifecycle and number of instances of IDataContext that Unity creates.
http://msdn.microsoft.com/en-us/library/cc440953.aspx
It sounds like the ContainerControlledLifetimeManager object will give you the instance management that you need. With that LifetimeManager in place, Unity should add the same instance of the IDataContext to all objects that require an IDataContext dependency.

Categories

Resources