Search code examples
.netasp.net-web-apidependency-injectionunity-container

Unity Container - Dependency Injection of Dynamic DbContext into Service


I'm building a .Net Web API which uses a Service+Repository pattern w/ Entity Framework. Each controller's CRUD actions relay data retrieved by calls to a Service.

I have a SomeContext that extends DbContext:

public class SomeContext : DbContext
{
    public SomeContext(string connString) : base(connString) { }

    // DbSets
    ...
}

The Service is initialized w/ a constructor that accepts an ISomeContext:

public class Service : IService
{
    public Service(ISomeContext ctx) : base(ctx)
    {
        _alpha = new AlphaRepository(ctx);
        ...
    }

    GetAllAlpha()
    {
        return _alpha.Get();
    }
    ...
}

I want to use (Unity Container) Dependency Injection to inject an instance of SomeContext into the Service constructor. The life cycle of a given SomeContext should be the duration of the API request. The difficulty is that the connection string for SomeContext is dynamic and cannot be known until a runtime parameter 'client' is provided as part of the API request.

Furthermore, there are an indeterminate number of clients and therefore connection strings due to my database-per-tenant environment. As such, I cannot just register n known SomeContexts and Resolve() based on the 'client' parameter.

Instead, an internally developed NuGet package w/ exposed ContextFactory lets me retrieve the appropriate SomeContext for a client:

ContextFactory.GetClientContext(client);

How and where do I configure Unity Container to manage this dynamic SomeContext?

Additional notes:

  • Unity is already dependency injecting the IService Service into each of my Controller actions. Because of this, the Service constructor is executed prior to any of the Web API ActionFilters I have created. This means I can't identify the 'client' prior to the injection...I presume this means I would need to use a factory and/or delegate...?
  • I've read about using an abstract factory in conjunction with a delegate for the DbContext, public delegate IDbContext CreateDbContext(string client);, and adapter for the NuGet package's GetClientContext request, but I haven't been able to piece it all together into a working solution.

Thanks for any help!


Solution

  • The trick to incorporate runtime parameters into a Unity Dependency Injected object is InjectionFactory:

    container.RegisterType<ISomeContext>(
        new PerRequestLifetimeManager(),
        new InjectionFactory(_ => ContextFactoryAdapter.GetSomeContext(new HttpContextWrapper(HttpContext.Current)))
    );
    

    InjectionFactory lets you specify a factory method the container will use to create the object

    In this case, I designate the static ContextFactoryAdapter.GetSomeContext() method to return a dynamic SomeContext according to data available in the supplied HttpContextWrapper argument:

    public static SomeContext GetSomeContext(HttpContextWrapper requestWrapper)
    {
        var client = requestWrapper.Request.QueryString["client"];
    
        return ContextFactory.GetClientContext(client);
    }
    

    So, Unity will resolve ISomeContext type to the SomeContext returned by GetClientContext().

    The PerRequestLifetimeManager() argument to RegisterType() instructs Unity to use the returned SomeContext instance for the lifetime of a single HTTP request. For Unity to dispose of the instance automatically, you must also also register the UnityPerRequestHttpModule in UnityMvcActivator.cs:

    DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
    

    With these configurations in place, Unity is able to resolve an appropriate SomeContext and supply this instance to the Service via constructor injection.