Question

I've recently refactored my MVC application to use Unity dependency injection to resolve dependencies, which is great. It's much more decomposable, etc., etc.

What I'm doing now is adding the capability for multiple tenants to use it. The approach I'm using (so that the rest of the code doesn't have to know much about the tenants) is creating things like a tenant-filtered version of my repository interface (which is just a proxy for another repository... so it will call one of the underlying methods, then check if the record has the right tenant and behave accordingly). This lets me basically emulate having a totally separate store for each tenant even though under the hood the data is not segregated, so relatively little of the client code needs to change.

The problem with all of this is how it fits into the DI way of doing things. What I'm planning to do is, at the beginning of the request, detect the host name, then use that to determine the tenant (each tenant will have a list of hostnames in the DB). Although I'm using per-request lifetimes for most objects Unity is constructing and resolving I don't really get how Unity can "know" what tenant to use since it would need both the data about the request (which I suppose the controller will have, but I don't think is available in my container configuration method) and access to the database to know which host (and it hardly seems desirable to have my container configuration making database calls). I can solve #2 by only passing in a host name and making the classes with tenants go figure out which tenant is being referenced, but that doesn't help with #1.

Right now I'm using "property injection" (also known as "a public property" in less high-falutin' circles), but I don't see how I'm going to avoid having my controller be the one that actually feeds the tenant data in, so now I don't really have just the one composition root controlling everything.

Is there a way I can do this in the composition root, or should I just resign myself to having the controller do this work?

Was it helpful?

Solution

For some reason you seem to forget about injection factories. Registering interface/type against a factory lets you execute arbitrarily complicated code upon resolving, including consulting the request, tenant database, whatever.

 container.RegisterType<IRepository>( 
     new InjectionFactory( 
        c => {
           // whatever, consult the database
           // whatever, consult the url
           return ...; 
        } );

The factory composition is transparent so that whenever you need it, the target doesn't even know that the factory code has been executed rather than a type instance from simple mapping.

OTHER TIPS

Somewhere it needs to make a database call. Maybe the simplest place would be in global.ascx if it's needed system wide.

private static ConcurrentDictionary<string, string> _tenantCache = new ConcurrentDictionary<string, string>();

protected virtual void Application_BeginRequest(object sender, EventArgs e)
{
    HttpApplication app = (HttpApplication)source;
    var tenantId = _tenantCache.GetOrAdd(app.Context.Request.Url.Host, host =>
            {
               // Make database call in this class
                var tenant = new TenantResolver();
                return tenant.GetTenantId(host);
            })
    app.Context.Items["TenantID"] = tenantId ;
}

You will want to cache the result as Application_BeginRequest is called alot. You can then configure Unity to have child containers. Put all the common/default mappings in the parent container then create a child container per tenant and register the correct implementation for each tenant in it's own child container.

Then implement IDependencyResolver to return the correct child container.

public class TenantDependencyResolver : IDependencyResolver
{
    private static IUnityContainer _parentContainer;
    private static IDictionary<string, IUnityContainer> _childContainers = new Dictionary<string, IUnityContainer>();

    public TenantDependencyResolver()
    {
        var fakeTenentID = "localhost";
        var fakeTenentContainer = _parentContainer.CreateChildContainer();
        // register any specific fakeTenent Interfaces to classes here

        //Add the child container to the dictionary for use later
        _childContainers[fakeTenentID] = fakeTenentContainer;
    }

    private IUnityContainer GetContainer()
    {
        var tenantID = HttpContext.Current.Items["TenantID"].ToString();
        if (_childContainers.ContainsKey(tenantID)
        {
            return _childContainers[tenantID];
        }
        return _parentContainer;
    }

    public object GetService(Type serviceType)
    {
        var container = GetContainer();
        return container.Resolve(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var container = GetContainer();
        return container.ResolveAll(serviceType);
    }
}

Then set ASP.NET MVC DependecyResolver to be the TenantDependencyResolver. I didn't run this code but it should give you an idea of what you would need to do. If your implementations are set then you might be able to do it in the static constructor of TenantDependecyResolver.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top