A topic for a future post perhaps, it would be really interesting to see how you would architect a web application with a contextual session management that supports multi tenancy that is a scalable keeping in mind the possibility of web farms / load balancers.
I spoke about this in my DevTeach talks about advanced OR/M and IoC. Let us start by defining multi tenancy. It is the ability to serve several customers on the same installed application. What do I mean by that?
Wikipedia defines Multitenancy as:
Multitenancy refers to the architectural principle, where a single instance of the software runs on a software-as-a-service (SaaS) vendor's servers, serving multiple client organizations (tenants). Multitenancy is contrasted with a multi-instance architecture where separate software instances (or hardware systems) are set up for different client organizations. With a multitenant architecture, a software application is designed to virtually partition its data and configuration so that each client organization works with a customized virtual application instance.
Broadly, there are three major challenges for multi tenant applications:
- Ensuring separation between the data of each client.
- Allowing customization of the data for each client.
- Allowing customization of behavior for each client.
For the first point, I tend to use a separate database per client, this make it significantly easier to deal with a lot of tasks, chief among them is that you literally can't accidentally expose another client data and letting the client access his own data is trivial (especially important if client want to get backups of his data).
For the second and third, I use the idea of the context.
The context is just that, the current context of whatever work we are performing. As a simple example, the context will contain the current user, how to access the database, the relevant services, etc. The context is an important concept, although I tend to favor implicit context rather than the explicit one.
An explicit context is something like this:
Or perhaps using an IContext with the same approach. It explicitly wraps all the contextual parts of the application.
As I said, I prefer to have an implicit context, where I don't explicitly need to deal with the context, rather, each of the service and data items that are present in the context. Rather, I deal with the contextual issue by extending the container to understand how it should deal with the context. That is, resolving the IAuthenticationService is an operation that is based on the business logic related to the current context.
This allows me more freedom overall and ensure that I don't have such things as DoSomething(IContext context), which doesn't really give me any hint about what it is doing.
Now, how does the idea of context allow me to deal with multi tenancy?
Quite simply, actually. For data customization, I simply create a separate session factory per each client, they can make whatever changes they want, and I can create a derived model on top of the default one, to match their needs. The usage of the base model means that I can still work with all the default services, and let NHibernate take the brunt of dealing with the modified schema and data.
For behavior customization, I have two options. If the behavior is part of the model, than obvious it should go in the derived model. If it is part of the services that we built for the application, we can simple build a derived service with the requested behavior and add it as part of the specified customer context.
This approach hugely simplify the need to deal with complex requirements such as multi tenancy. The real secret, I must confess, is that from the point of view of the application, this multi tenancy is not really felt. It just happens.