Introducing AutofacContrib.Multitenant - Multitenant Dependency Injection with Autofac

347 views
Skip to first unread message

tillig

unread,
Jul 28, 2010, 5:50:07 PM7/28/10
to Autofac
As blogged here (http://www.paraesthesia.com/archive/2010/07/28/
introducing-autofaccontrib.multitenant-multitenant-dependency-
injection-with-autofac.aspx), it's taken some time and a couple of
long Google Groups threads, but with a kick in the right direction
from Nick Blumhardt, I've got multitenant dependency injection working
with Autofac and available as a contributed library.

The basic usage pattern is:

* Determine a strategy by which tenants are identified. That is, which
tenant is making a given request? This might come from an environment
variable, a request parameter, a role on the user's principal, or
wherever.
* Build up your application container with the default dependency set.
For tenants that don't override anything, they'll use these defaults.
* Create a multitenant-aware container based on the application
defaults. This is where the magic of AutofacContrib.Multitenant comes
into play.
* Configure tenant-specific overrides with the multitenant-aware
container. Tenants can override things, add new dependencies, or
whatever they need to do.
* Resolve everything out of the multitenant-aware container. All of
the resolutions will automatically use your tenant identification
strategy so you'll always get a tenant-specific result.

In practice, it looks like something this:


// First, create your application-level defaults using a standard
// ContainerBuilder, just as you are used to.
var builder = new ContainerBuilder();
builder.RegisterType().As().InstancePerDependency();
builder.RegisterType().As().SingleInstance();
var appContainer = builder.Build();

// Once you've built the application-level default container, you
// need to create a tenant identification strategy.
var tenantIdentifier = new MyTenantIdentificationStrategy();

// Now create the multitenant container using the application
// container and the tenant identification strategy.
var mtc = new MultitenantContainer(tenantIdentifier, appContainer);

// Configure the overrides for each tenant by passing in the tenant ID
// and a lambda that takes a ContainerBuilder.
mtc.ConfigureTenant('1', b =>
b.RegisterType().As().InstancePerDependency());
mtc.ConfigureTenant('2', b => b.RegisterType().As().SingleInstance());

// Now you can use the multitenant container to resolve instances.
// Resolutions will be tenant-specific.
var dependency = mtc.Resolve();


The usage is very similar to the existing Autofac usage you know and
love.

The multitenancy support works for standard non-web/service apps
(e.g., console apps or Windows services), ASP.NET web forms and MVC
apps, and WCF service apps.

There's a ton of documentation (http://code.google.com/p/autofac/wiki/
MultitenantIntegration) about how to use the multitenancy that
includes sample code snippets. There are also some sample console,
WCF, and ASP.NET MVC applications in the source tree so you can see it
in action.

It's not currently out there as a binary, so you'll have to do a
source checkout and compile it manually, but I'm sure it'll show up
soon.

We're looking for early adopters to give us feedback on it. If you try
it out, please let us know what you think in the Autofac Google Group.
What did you like? What were the pain points? Did you find a scenario
that didn't work? How was the documentation? The more feedback we get,
the better we can make it! Thanks!

tillig

unread,
Jul 28, 2010, 5:57:09 PM7/28/10
to Autofac
Oops, there are some typos/errors in my sample code snippet due to
HTML encoding issues with my copy/paste. Lemme try that again.

Sample usage:

// First, create your application-level defaults using a standard
// ContainerBuilder, just as you are used to.
var builder = new ContainerBuilder();
builder.RegisterType<Consumer>().As<IDependencyConsumer>().InstancePerDependency();
builder.RegisterType<BaseDependency>().As<IDependency>().SingleInstance();
var appContainer = builder.Build();

// Once you've built the application-level default container, you
// need to create a tenant identification strategy.
var tenantIdentifier = new MyTenantIdentificationStrategy();

// Now create the multitenant container using the application
// container and the tenant identification strategy.
var mtc = new MultitenantContainer(tenantIdentifier, appContainer);

// Configure the overrides for each tenant by passing in the tenant ID
// and a lambda that takes a ContainerBuilder.
mtc.ConfigureTenant('1', b =>
b.RegisterType<Tenant1Dependency>().As<IDependency>().InstancePerDependency());
mtc.ConfigureTenant('2', b =>
b.RegisterType<Tenant2Dependency>().As<IDependency>().SingleInstance());

// Now you can use the multitenant container to resolve instances.
// Resolutions will be tenant-specific.
var dependency = mtc.Resolve<IDependency>();

Luke Schafer

unread,
Jul 28, 2010, 6:54:26 PM7/28/10
to aut...@googlegroups.com
Hi Travis.

Well done, that looks fantastic. Very clean.

I haven't looked at the code but I couldn't see if the api supports a tenant-aware component resolving for a given tenant - this removes the need for threadstatic variables available to the strategy. I can only think of a couple of cases where you would even consider this (admittedly it's resolvable by using a threadstatic), but I can't help but think it might be useful for someone.

Also you mention that a tenant can only be configured once. Is this by design or constraint?

Regards,

Luke

--
You received this message because you are subscribed to the Google Groups "Autofac" group.
To post to this group, send email to aut...@googlegroups.com.
To unsubscribe from this group, send email to autofac+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/autofac?hl=en.


tillig

unread,
Jul 29, 2010, 12:35:21 PM7/29/10
to Autofac
In order to determine a tenant there is an interface you can
implement. You can determine the tenant ID from anywhere you want -
environment, request parameter, thread, user principal, or whatever. I
have some documentation outlining how it works here:
http://code.google.com/p/autofac/wiki/MultitenantIntegration#Tenant_Identification

The tenant ID mechanism is an application/container-level thing
because if you had a tenant-specific way of identifying the tenant...
you've got a chicken/egg problem. :)

Tenants can only be configured once because each tenant basically gets
a LifetimeScope where you register tenant-specific dependencies. It's
roughly the same as calling IContainer.BeginLifetimeScope(lambda) for
each tenant. You can't really update the contents of a custom lifetime
scope. The choice to use lifetime scopes rather than per-tenant
containers is due to the need to be able to "inherit" application
defaults at the tenant level. Lifetime scopes are the inheritance
mechanism in Autofac 2.x rather than inner containers like in 1.x

If you need to build up a tenant configuration over the course of some
business logic, a ConfigurationActionBuilder is provided:
http://code.google.com/p/autofac/wiki/MultitenantIntegration#Registering_Dependencies

So while you can't call ConfigureTenant() several times for a given
tenant, you can build up a tenant's configuration over the course of
whatever application logic you have and configure them all at once,
similar to the ContainerBuilder pattern that exists for core Autofac.

Check out the doc in the wiki if you haven't already, I walk through a
few examples and snippets to help illustrate how it works.
http://code.google.com/p/autofac/wiki/MultitenantIntegration

Hope that helps,
-T
> > autofac+u...@googlegroups.com<autofac%2Bunsu...@googlegroups.com>
> > .
Reply all
Reply to author
Forward
0 new messages