Can I use an IoC container to create a dependency that requires a runtime value?
I'm an IoC newbie, so I'm wondering if it's even the right tool for the job I want to do.
I'm writing a multi-tenant application, and there are several places that we might want to use different implementations of interfaces based on the organization to which the currently logged-on user belongs.
Say, for example, when a user from one organization creates a work or开发者_如何学JAVAder, that user's supervisor needs to be sent an email. But for all other organizations, that email doesn't need to be sent. Classic strategy pattern kind of thing.
My question is, can I somehow instruct the IoC container to look at a certain runtime value (the OrganizationId
of the logged on user in this case) to determine which implementation of the IWorkOrderProcessor
to inject into the constructor of the object that needs it?
I'm currently using Windsor, but examples using other containers would be fine.
Windsor has an extension point that is a perfect fit for multi-tenant apps: IHandlerSelector.
- http://ayende.com/Blog/archive/2008/10/05/windsor-ihandlerselector.aspx
- http://mikehadlow.blogspot.com/2008/11/multi-tenancy-part-2-components-and.html
This lets you code your application as if it wasn't multi-tenant. Multi-tenancy logic is moved out of your business logic.
Most good IOC containers will support this sort of usage.
I'm not familiar with Windsor, my IOC of choice is StructureMap. In the StructureMap fluent interface you have lots of options for setting up runtime injected parameters of objectsm depending on pretty much anything you can express in code. I'm sure Windsor offers the same.
The only thing I's say about using IOC like this is that sometime it would actually make a solution harder to understand.
In your example, if you really have a true use case for strategy pattern where you would implement this behaviour even were you not using IOC as an injected strategy object (using some Factory approach) then I'd say, yes, go ahead with the IOC implementation.
But if you don't really need to inject a whole object abstraction for expressing the logic of whether certain users get emails, then perhaps this would be a case of patterns for the sake of patterns.
This is a common challenge with DI, and the answer is always to create and inject an Abstract Factory. In your case, you can define an interface like this:
public interface IWorkerProcessorFactory
{
IWorkerProcessor Create(int organizationId);
}
In all the classes where you have an organization ID and need an instance of IWorkerProcessor, you take a dependency on IWorkerProcessorFactory and invoke its Create method.
This pattern works with Poor Man's DI or just about any DI Container you would like to use.
Here's a more complete example: Can't combine Factory / DI
I think You can, because IoC container can use different types of injection:
- a constructor injection,
- a setter injection,
- an interface injection (method injection)
Constructor injection gives the fully initialized object but types and values You are injecting have to be known just before the object is created (e.g might be loaded from configuration file).
Method (or setter) injection is flexible - You can delay injection until You desired type or value. Disadvantage of this approach is that You do not have fully initialized object when You create it.
Everything depends of how Your container is implemented.
By the way: similar questions was asked: IoC: Existing runtime objects rather than container-initialised prerequisites for components
精彩评论