1

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?

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
Beachwalker
  • 7,685
  • 6
  • 52
  • 94

1 Answers1

2

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... ;-)

Beachwalker
  • 7,685
  • 6
  • 52
  • 94
  • 1
    This solution sounds good to me. Which kind of issue are you thinking about with it ? By the way, if you have a big application, I would recommend you to look at the source code of the Multitenant extension, it is quite simple and in some case, it is better to fork it and to adapt it for your own case. This is what I did for a large application. – Cyril Durand Apr 11 '15 at 12:47
  • @CyrilDurand What are the reasons for the fork? – Beachwalker Jun 02 '15 at 09:20
  • The *multitenant* autofac extension is really tiny and simple, I used it as a sample implementation for multitenant application. I don't remember why I didn't use it as such but I think I needed more control and more extensibility point. – Cyril Durand Jun 02 '15 at 09:28