How is it possible to use Autofac's Modules combined with the Multitenant package?
This is my bootstrapping part for Autofac:
var builder = new ContainerBuilder();
// only very basic common registrations here...
// everything else is in modules
// Register the Autofac module for xml configuration as last
// module to allow (emergency) overrides.
builder.RegisterModule(new ConfigurationSettingsReader());
// create container for IoC
this.container = builder.Build();
// check for tenant strategy -> if exists, go multi-tenant
if (this.container.IsRegistered<ITenantIdentificationStrategy>())
{
var tenantIdentificationStrategy = this.container
.Resolve<ITenantIdentificationStrategy>();
this.container = new MultitenantContainer(tenantIdentificationStrategy,
this.container);
// how to use xml modules instead of manually register at this point?
}
else
{ ... }
I don't want to call something like
container.ConfigureTenant('1', b => b.RegisterType<Tenant1Dependency>()
.As<IDependency>()
.InstancePerDependency());
within the bootstrapper (which don't need to know something about this).
Instead I want to do something like this:
public class TenantModule : Module
{
protected override void Load(ContainerBuilder builder)
{
container.ConfigureTenant('1', b => b.RegisterType<Tenant1Dependency>()
.As<IDependency>()
.InstancePerDependency());
container.ConfigureTenant('2', b => b.RegisterType<Tenant2Dependency>()
.As<IDependency>()
.InstancePerDependency());
...
My first idea was to check when registering something for a special tenant:
public class TenantModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register((c, p) => {
var s = c.Resolve<ITenantIdentificationStrategy>();
if (s != null)
{
var id = s.IdentifyTenant<string>();
...
}
});
I could check the id and register only if id fits, but what to return if id is not matching? null? DoNothingObject? Looks strange/horrible in code to me and something like
builder.Register("1", (context, parameters) => ...
feels more natural. But I don't know how to achieve this out of the box with Autofac. Did I miss something? How did you solved that problem?
Missed the point that ConfigureTenant also passes the containerBuilder which allows the registration of a tenant specific ConfigurationSectionReader. So an option is to have an additional customer/tenant specific ConfigurationSection:
mtc.ConfigureTenant("mytenant1",
containerBuilder =>
{
containerBuilder.RegisterModule(new ConfigurationSettingsReader("mytenant1"));
}
);
mtc.ConfigureTenant("mytenant2",
containerBuilder =>
{
containerBuilder.RegisterModule(new ConfigurationSettingsReader("mytenant2"));
}
);
This also leads me to the point that I can resolve the tenant identification strategy first, get the identifier and make only the registrations for the current tenant (like a customer specific bootstrap):
var tenantIdentificationStrategy = container.Resolve<ITenantIdentificationStrategy>();
var tid = tenantIdentificationStrategy.IdentifyTenant<string>();
mtc.ConfigureTenant(tid ,
containerBuilder =>
{
containerBuilder.RegisterModule(new ConfigurationSettingsReader(tid));
// or something like that which identifies the tenant config section
}
);
Or I could put this into a simple foreach to make registrations for all available tenants (but this sounds curious in most scenarios here because only one tenant will be resolved at time at its a bootstrapping part, maybe for other special cases worth to mention).
Any better ideas? I'll vote up for better ideas... ;-)