Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have multiple dependency resolvers in ASP.NET MVC 3?

Is it possible to have more than one dependency resolver in ASP.NET MVC 3 (similar to the case of ModelBinders and Providers)?

like image 757
Guillermo Gutiérrez Avatar asked Jan 13 '23 17:01

Guillermo Gutiérrez


1 Answers

There is one scenario that I could think of where having multiple 'containers' or 'resolvers' is useful and that is multi-tenancy. With multi tenancy you run multiple customers (organizations, with their own set of users) in the same web application, and dynamically switch based on the login, request info, or domain info.

Still, DependencyResolver.Current is -as Darin noted- static, so there's nothing you can (or should do about this). However, you could hide multiple containers behind a single IDependencyResolver abstraction and return an implementation based on some criteria. It might look like this:

public class MultiTenantDependencyResolver 
    : IDependencyResolver
{
    Func<int> tenantIdSelector,;
    IDictionary<int, IDependencyResolver> tenantResolvers;

    public MultiTenantDependencyResolver(
        Func<int> tenantIdSelector,
        IDictionary<int, IDependencyResolver> tenantResolvers)
    {
        this.tenantIdSelector = tenantIdSelector;
        this.tenantResolvers= tenantResolvers;
    }

    private IDependencyResolver CurrentResolver
    { 
        get { return this.tenantResolvers[tenantIdSelector()]; }
    }

    public object GetService(Type serviceType)
    {
        return this.CurrentResolver.GetService(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.CurrentResolver.GetAllInstances(serviceType);
    }
}

The following code snippet shows the usage of this MultiTenantDependencyResolver:

var tenantResolvers = new Dictionary<int, IDependencyResolver>
{
    { Tenants.AbcId, BuildResolver(RegisterForTenantAbc) },
    { Tenants.KlmId, BuildResolver(RegisterForTenantKlm) },
    { Tenants.XyzId, BuildResolver(RegisterForTenantXyz) },
};

var multiTenantResolver = new MultiTenantResolver(
    () => GetTenantIdFromUrl(), tenantResolvers);

DependencyResolver.SetResolver(multiTenantResolver);


private static int GetTenantIdFromUrl()
{
    // TODO: return tenant id
}

private static IDependencyResolver BuildResolver(
    Action<IKernel> tenantSpecificRegistrations)
{
    var kernel = new Kernel();

    // TODO: Tenant agnostic registrations. For instance
    kernel.Bind<ITimeProvider>().To<SystemTimeProvider>();

    tenantSpecificRegistrations(kernel);

    return new NinjectDependencyResolver(kernel);
}

private static void RegisterForTenantAbc(IKernel kernel)
{
    // TODO: regisrations for ABC tenant. For instance
    kernel.Bind<ILogger>().To<AbcTenantLogger>();
}
like image 97
Steven Avatar answered Jan 22 '23 19:01

Steven