Multitenant Application – Part 2: Context driven dependency injection

Further to the previous post, object creation based on the current context is a cross cutting concern, so it should be dragged outside the core business logic. We have already tried creating a factory method to give us the required implementation. We will now replace this with a container to allow Inversion Of Control.

The most simplest way to implement this would be registering the named mappings of the implementations, where the name of the mapping would be the context value. e.g.

//register at application start up
container.Register(Component.For<IGreetingService>()
   .ImplementedBy<EnglishGreeting>().Named("UK"));

container.Register(Component.For<IGreetingService>()
   .ImplementedBy<SpanishGreeting>().Named("SPAIN")); 

//resolve as a factory to get context driven implementation 
container.Resolve(ContextProvider.CurrentCountry);

If you have read the previous post, we have reduced to one “if” condition per implementation in the factory method. The above code would get rid of the remaining ‘if’ or ‘switch’ statement in the factory method. This is not too bad, but we can do better than this by using the power of extensible containers. Another problem with this approach is the Service Locator pattern, which is being accused of being an anti pattern. I personally prefer Dependency Injection over this.

We will continue with the idea of registering the named implementation but will create more flexible mechanism to specify the context provider of choice. This means that while some mappings can use CountryCode, the others could choose to use ClientCode.

Lets assume our implementation is based on the country code, which will be provided by an implementation of IContextProvider class.

public interface IContextProvider
{
    string CurrentCountry { get; set; }
}

Our factory/container will resolve the dependency based on the value of CurrentCountry property of an instance of IContextProvider. As discussed earlier, this as a cross cutting concern, hence the implementation should be as less intrusive as possible to the main business logic. In these cases I prefer declarative over imperative, which makes attribute an ideal candidate by providing transparent implementation.

public class ContextualDependencyAttribute : Attribute
{
    public Type ContextProviderType { get; set; }
    public string SettingName { get; set; }
}

This attribute will contain the metadata about how to get the context value. i.e Type of context provider and the property to read the value from.

[ContextualDependency(
  ContextProviderType = typeof(IContextProvider), 
  SettingName = "CurrentCountry")]
public interface IGreetingService
{
   string Greet(string name);
}

The above interface is declaring its context provider as of IContextProvider type and specify a property called CurrentCountry to get the name of the implementation.

I am going to use Castle Windsor as my container, which provides a very convenient extension point called IHandlerSelector. It has two methods, one is to filter the dependencies it can deal with (HasOpinionAbout) and the other is to get the handler to resolve dependency (SelectHanlder).

public class ContextBasedFactorySelector: IHandlerSelector 
{
	
    private readonly IKernel kernel;

	public ContextBasedFactorySelector(IKernel kernel) {
		this.kernel = kernel;
	}

	public bool HasOpinionAbout(string key, Type service) {
		return service.HasAttribute<ContextualDependencyAttribute>();
	}

	public IHandler SelectHandler(string key, Type service, IHandler[] handlers) {
		var attribute = service.GetAttribute<ContextualDependencyAttribute>();
		if (attribute == null) {
			throw new InvalidOperationException("ContextualDependencyAttribute was expected");
		}
		var contextProvider = this.kernel.Resolve(attribute.ContextProviderType);
		var contextSettingGetter = attribute.ContextProviderType.GetProperty(attribute.SettingName);
		var handler = handlers.FirstOrDefault(h = > h.ComponentModel.Name == (string) contextSettingGetter.GetValue(contextProvider));
		if (handler == null) {
			throw new InvalidOperationException("ContextualDependencyAttribute was expected");
		}
		return handler;
	}
}

In SelectHandler, we will read the attribute (ContextualDependencyAttribute) of requested component. From the attribute, we will know the type of context provider to resolve and then we will read its specified property (using reflection) to get the value for the name of the implementation (i.e. IContextProvider.CurrentCountry). After reading the value it is just a matter of resolving the dependency with the name.

We can go further it by extending the attribute to use on the implementation instead of interface. Then with the help of reflection, registration will be quite simple and manageable.

[ContextualDependencyAttribute(
  ContextProvider="IContextProvider", 
  Setting="Client",Value="AbcLtd")]
public class AbcBusinessLogic: IBusinessLogic
{
}

However this implementation can serve in almost all the layers by resolving the context based dependency injection, there are even more suitable points provided by some frameworks to provide flexible implementation such as multi-tenant, global or media responsive code. e.g. MVC action selector, displaymode etc. I will discuss that some other time.

One thought on “Multitenant Application – Part 2: Context driven dependency injection

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s