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:
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!
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.