Implementing A Multi-Tenant ASP.NET MVC Application with S#arp Architecture

Back to Listing

Implementing A Multi-Tenant ASP.NET MVC Application with S#arp Architecture


08 Aug, 2009


I love me some S#arp Architecture! I subscribe to the mailing list where users ask questions about it’s usage and I try to help when I can. Recently, Paul Hinett of UK Creative Designs asked the following question:

Hi Everyone.

I’m very new to NHibernate, Fluent & S#arp but I’m very keen to learn and have an idea of how OOP and DDD works.

One question I have though is if it’s possible to some way extend the IRepository class, at the moment it provides some basic CRUD functions such as Get, GetAll etc...

However, for this project I am creating for virtually every call to the database i need to pass  a SiteId to filter the data, i thought it would be easier to extend the IRepositroy class itself rather than creating 15-20 interfaces which inherit the IRepository class (like the Northwind example project has done for a couple of classes) and add my own functions.

Sorry if any of my terminology is incorrect, hope you understand what i mean!

Regards, Paul Hinett

The entire thread is a good read and I suggest reading the whole thing for context. What Paul is talking about is a Multi-Tenant application. For a great tutorial on what muli-tenancy is check out Ayende’s excellent series on the subject which starts here and ends here. Sadly, Ayende never went back and finished his series on the topic, but he does still talk on the subject at conferences. I was lucky enough to attend his workshop at ALT.NET Seattle this year. He even has a sample application you can look that demonstrates the key concepts.

S#arp Architecture has multiple database support built in at the Repository level. What this means is that I can have a UserRepository that uses the default nhibernate configuration and then a separate ContentRepository using a different configuration. To accomplish this all you need to do is attribute your Repository with a SessionFactory key like this:

  [SessionFactory("content")]
  public class ContentRepository : Repository
  {  }

There is also some other configuration stuff you need to do for this to work, I’ll get to that in a bit.

What Paul wants to be able to do is to have NHibernate talk to different databases based on some bit of the URL. So, if the user accesses the site via http://www.havartirocks.com it talks to the HavartiCheese database, but if they come in using http://www.provaloneowns.com they talk to the ProvaloneCheese database. He ads the extra wrinkle in that he would like a third common database for things like User accounts.

The best way I have found to approach this kind of problem is to start with the domain and let it tell the infrastructure how to react to it. So given the following simple classes, I would like the User class to be persisted to a common core database and the Orders & LineItems classes to be persisted to their respective Tenant databases.

namespace CheeseStore.Core  
{
  public class User : Entity
  {
    public virtual string Name { get; set; }
  }

  public class Order : Entity
  {
    public virtual DateTime OrderDate { get; set; }
    public virtual DateTime ShipDate { get; set; }
    public virtual IList Items { get; set; }
  }

  public class LineItem : Entity
  {
    public virtual string SKU { get; set; }
    public virtual int Quantity { get; set; }
  }
}

All of my domain classes inherit from the S#arp Architecture base class Entity. This gives me a lot of preconfigured persistence support via NHibernate for my domain classes. Next, I need some way in my domain to identify entities that are tenant specific. The simplest way to do this is with a marker interface. A marker interface has no implementation and as it’s name suggests it simply marks a class so that it is easy to detect via reflection. The above domain now looks like this:

namespace CheeseStore.Core  
{
  public interface IAmTenantSpecific
  {  }

  public class User : Entity
  {
    public virtual string Name { get; set; }
  }

  public class Order : Entity, IAmTenantSpecific
  {
    public virtual DateTime OrderDate { get; set; }
    public virtual DateTime ShipDate { get; set; }
    public virtual IList Items { get; set; }
  }

  public class LineItem : Entity, IAmTenantSpecific
  {
    public virtual string SKU { get; set; }
    public virtual int Quantity { get; set; }
  }
}

We can now clearly see that Orders and LineItems are meant to be considered as multitenant objects. Since S#arp’s Repository class doesn’t support switching databases on the fly, I need to create my own implementation class that will do this for me. I can inherit directly from Repository and just override the bits I need.

namespace CheeseStore.Core  
{
  public interface ITenantContext
  {
    string GetFactoryKey();
  }
}
namespace CheeseStore.Data  
{
  public class MultiTenantRepository : Repository
  {
    private ITenantContext tenantContext;

    public MultiTenantRepository(ITenantContext tenantContext)
    {
      this.tenantContext = tenantContext;
    }

    protected override ISession Session
    {
      get
      {
        string factoryKey = tenantContext.GetFactoryKey();
        return factoryKey == null ? base.Session : NHibernateSession.CurrentFor(factoryKey);
      }
    }
  }
}

There are a couple interesting things going on here. First is the interface ITenantContext. You notice that it lives in the CheeseStore.Core namespace in a project of the same name. My application needs some way to determine what the tenant is, at this point I don’t really care how or where. I just want to define the contract that states that something will provide this bit of information for the Repository. Next, we have the MultiTenantRepository it inherits form the S#arp provided Repository implementation and simply overrides its Session property. This property relies on the tenant context to provide the key and then pulls it out of the S#arp provided session factory class. Finally, notice that the tenant context is provided though constructor injection. We will have to wire that up later once we have an implementation.

I can now easily create a Order specific repository like this:

namespace CheeseStore.Core.DataInterfaces  
{
  public interface IOrderRepository
  {
    IList GetBySomeCriteria(int count);
  }
}

namespace CheeseStore.Data  
{
  public class OrderRepository : MultiTenantRepository, IOrderRepository
  {
    public OrderRepository(ITenantContext tenantContext) : base(tenantContext)
    {
    }

    public IList GetBySomeCriteria(int count)
    {
      ICriteria criteria = Session.CreateCriteria(typeof(Order));
      return criteria.List();
    }
  }
}

This is exactly how the S#arp architecture documents instruct you to create a entity specific repository with a defining interface and implementation that leans on the base Repository class.

Next up we need a way to configure the S#arp NHibernate session factory factory with multiple configurations. This configuration is almost wired up for us already, we simply need to edit the InitalizeNHibernateSession() method in the Global.asax and add a couple tricky tweaks to the AutoPersistenceModelGenerator class to take advantage of our marker interface.

Here is the change to the Global:

   /// 
    /// If you need to communicate to multiple databases, you'd add a line to this method to
    /// initialize the other database as well.
    /// 
    private void InitializeNHibernateSession()
    {
      NHibernateSession.Init(
         new WebSessionStorage(this),
          new string[] { Server.MapPath("~/bin/CheeseStore.Data.dll") },
          new AutoPersistenceModelGenerator().GenerateCore(),
          Server.MapPath("~/Config/CoreNHibernate.config"));

      NHibernateSession.Init(
         new WebSessionStorage(this,"Tenant1"),
          new string[] { Server.MapPath("~/bin/CheeseStore.Data.dll") },
          new AutoPersistenceModelGenerator().Generate(),
          Server.MapPath("~/Config/Tenant1NHibernate.config"));
    }

Notice that I first initialize the default core session factory and then initialize a tenant factory providing an tenant key to identify them by. I could add as many tenants as I want right here. Also note that each factory uses a separate nhibernate.config file so you can tweak all you want. The final thing to notice here is the call to AutoPersistenceModelGenerator.GenerateCore(). This is the additional tweak I mentioned earlier.

We want to be able to configure each session factory with a different set of domain objects. The core needs only core entities and each tenant needs the full set of multi-tenant entities. Here is how I accomplished that:

namespace CheeseStore.Data.NHibernateMaps  
{
  public class AutoPersistenceModelGenerator : IAutoPersistenceModelGenerator
  {
    private bool isTenantModel = true;

    public AutoPersistenceModel GenerateCore()
    {
      isTenantModel = false;
      return Generate();
    }

    public AutoPersistenceModel Generate()
    {
      AutoPersistenceModel mappings = AutoPersistenceModel
         .MapEntitiesFromAssemblyOf()
          .Where(GetAutoMappingFilter)
          .ConventionDiscovery.Setup(GetConventions())
          .WithSetup(GetSetup())
          .UseOverridesFromAssemblyOf();

      return mappings;
    }
   ...

    private bool GetAutoMappingFilter(Type t)
    {
      //see if the type is a tenant entity
      var tenantType = t.GetInterfaces().Any(x => x == typeof(IAmTenantSpecific));

      return t.GetInterfaces().Any(x =>
           x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>))
           && isTenantModel ? tenantType : !tenantType;
    }
    ...
  }
}

Here I have added a private member to indicate if we are generating a tenant model and a new method GenerateCore() that sets that property and calls the default functionality. I have also modified the GetAutoMappingFilter() method to divide my domain objects by the marker interface. Thus providing two totally different persistence models from one domain.

So far we started at the domain model and worked out way down to the data access layer. Next up we need to create a MVC Controller that uses our OrderRepository. No problem. It looks like every other controller with a dependency on a Repository.

namespace CheeseStore.Web.Controllers  
{
  [HandleError]
  public class HomeController : Controller
  {
    private IOrderRepository orderRepository;

    public HomeController(IOrderRepository orderRepository)
    {
      this.orderRepository = orderRepository;
    }

    public ActionResult Index()
    {
      return View();
    }
  }
}

Notice that our controller knows nothing about the multi-tenancy work we have been doing. It requests a IOrderRepository and does what ever it needs to do with it completely ignorant of where the objects are being persisted or even how.

There is one thing left to do here. We still haven’t specified where the tenant context comes from. For this example, I will keep it simple and base the tenant id off of a query string parameter. It could just as easily be based on the domain or a sub-domain. Here is what that looks like:

namespace CheeseStore.Web  
{
  public class TenantContext : ITenantContext
  {

    public string GetFactoryKey()
    {
      return HttpContext.Current.Request.QueryString.Get("tenantId");
    }
  }
}

It is that simple. This class actually lives in the ASP.NET MVC project. This allows the website to define how the tenant context is created.

If you are interested in taking a look at the complete solution you can download it here. A majority of what you see in the solution is auto generated by S#arp Architecture when you create a new project. So all credit goes to Billy and the other devs on S#arp for that. I have outlined my modifications above.

Share this story

Bobby Johnson

About Author

I am a passionate engineer with an interest in shipping quality software, building strong collaborative teams and continuous improvement of my skills, team and the product.

comments powered by Disqus
Back to top