views:

121

answers:

4

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 order, 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.

+1  A: 

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.

David Hall
A: 

I think You can, because IoC container can use different types of injection:

  1. a constructor injection,
  2. a setter injection,
  3. 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: http://stackoverflow.com/questions/1544343/ioc-existing-runtime-objects-rather-than-container-initialised-prerequisites-for

Dejw
*"types and values You are injecting have to be known at start-up of application (e.g loaded from configuration file)"* -> No.
Mauricio Scheffer
Right, I mean they have to be known just before object creation. My mistake. Fixed. Thank You.
Dejw
+2  A: 

Windsor has an extension point that is a perfect fit for multi-tenant apps: IHandlerSelector.

This lets you code your application as if it wasn't multi-tenant. Multi-tenancy logic is moved out of your business logic.

Mauricio Scheffer
Thanks, Mauricio! The IHandlerSelector feature is exactly what I was looking for!
Brian Sullivan
A: 

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: http://stackoverflow.com/questions/1926826/cant-combine-factory-di/1927167#1927167

Mark Seemann