I'm implementing StructureMap in a multi-tenant ASP.NET MVC application to inject instances of my tenant repositories that retrieve data based on an ITenantContext
interface. The Tenant
in question is determined from RouteData
in a base controller's OnActionExecuting
.
How do I tell StructureMap to construct TenantContext(tenantID);
where tenantID is derived from my RouteData
or some base controller property?
Given the following route:
{tenant}/{controller}/{action}/{id}
My base controller retrieves and stores the correct Tenant
based on the {tenant} URL parameter. Using Tenant
, a repository with an ITenantContext
can be constructed to retrieve only data that is relevant to that tenant.
Based on the other DI questions, could AbstractFactory
be a solution?
Do not store the tenant on the controller, as it will not be available to injected services, as you discovered. Create a thin service whose sole responsibility is to determine the tenant identifier. The service can access statics and HttpContext directly. This class doesn't really need to be unit-testable - its purpose is to isolate the rest of the system so that other classes are testable.
If you want ITenantContext
to be that service, it could look something like:
public class TenantContext : ITenantContext
{
public string GetTenant()
{
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
return routeData.GetRequiredString("tenant");
}
}
Now your controller can just have a dependency on your repository interface, and your repository implementation (an any other services that care) can depend on ITenantContext
. The controller doesn't need to know about tenants.
@FreshCode, I don´t know if you have a dependency on the repository directly in your controller or if your controller has a dependency on a service, which in turns, has a dependency on the repository. However, when the controller is instantiated by structuremap, the service or repository should be already instantiated. We determine the tenant on the Begin_Request and inject the instantiated context into structuremap, with the Inject method. That executes before the controller factory does, so when the controller is instantiated all it´s dependencies have already been created.
Regards.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With