Search code examples
asp.net-mvcasp.net-mvc-3multi-tenantaction-filter

Can I handle different multi-tenancy with a global filter?


I have an asp.net mvc app which has membership implemented. So a user has to log in. Each user belongs to a organisation (multi-tenancy).

How would I handle the organisation parameter globaly? I was thinking this could be a good thing for a global filter because all the data needs to be filtered for the given organisation. And the organisation is connected with the username but not in the same table.

for example I have a index action like this

public ActionResult Index()
{
var result = _repository.GetListByOrganisation(organisation);
return View(result);
}

I was thinking about having a global attribute thats queries the db for an organisation based on a giving username. Since my controller already contains the authorize attribute I have the user name. It would be nice to cache the organisation (session, controllercontext) and not query the organisation from db on each request.

Is this a way to implement something like this? Or are there other ways which would be better? And how can I set a property on the controller / controllercontext from whithin a filter?

So any thoughts on this as well as comments would be great...


Solution

  • I would do this via DI.

    You can use either a third-party DI container or your own code. Either way, you want to set the organization ID on a per-request basis.

    So you'll be creating a unit of work and injecting that in your controller. For the sake of simplicity, let's pretend that your unit of work is the _repository field in your sample code, even though most real-world apps are more complex.

    You add a constructor parameter to the controller:

    public FooController(IFooRepository repository)
    {
        this._repository = repository;
    }
    

    ...and an organization ID on FooRepository:

    public class FooRepository: IFooRepository
    {
        public FooRepository(long organizationId)
        {
            this._organizationId = organizationId;
        }
    }
    

    Now in either your DI container setup or a MVC controller factory, you set this all up:

    builder.Register(c => new FooRepository(GetOrgIdForCurrentUser()).As<IFooRepository>();
    builder.Register(c => new FooController(c.Resolve<IFooRepository>());