Multi-tenancy in ASP.NET MVC - Controller Actions (Part II)

(Or a post-mortem examination of what MvcEx taught me about MVC frameworks)

Previous entries in the series

A long time overdue (our multi-tenant product is nearly ready for release woohoo!) - I'm going to write a bit more about compositing controllers from "action containers" - which is how my reference multi-tenancy framework (MvcEx) currently does things. I want to explain my motivation for attempting that solution and to give a few opinions on the suitability of MS MVC for the task of building multi-tenant applications in this way.

As outlined in the previous entry about controller actions, when building a multi-tenant and internally extensible application it is convenient that modules be able to contribute actions (or more importantly, override existing actions) to supplement the views exposed by those modules.

The solution in the previous entry was to select the appropriate controller based on the context of the current request, but I was curious as to whether a neater solution could be created within our chosen framework to separate our concerns into application concerns and module concerns:

  • Give control of the application to the application itself (OnActionExecuting etc)
  • Give production of the actions to the action containers held in the modules

If I was building an MVC framework from scratch, I wouldn't have built a framework that forced you to inherit from a base class (Controller), with all the baggage and responsibility in one place like that, but it works for a lot of people and a lot of applications so I can't really complain too much...

Anyway, we are using MS MVC and are therefore have to live with these design decisions and can work around them as best we can to achieve what we want(as we have been doing so for the past few entries in this series)

The application needs to be able to intercept each action, to perform custom logic on models which are being received/sent to the client, to handle controller-specific errors etc.

The modules simply need to be able to provide actions, and ideally should be bound to the behaviour of the entire application so you don't get unexpected happenings down the line when you've written your 20th module and wonder why it's not working quite right. (Forgot to inherit from the right base class etc etc...)

It turns out that none of this is particularly easy, and the MvcEx solution was to create a framework which scans for classes labelled as being action containers (something with an attribute of MvcExActionContainer("Name")), gather together its methods and create a controller which derived from an application provided Controller with all the relevant actions created on it.

This required a lot of Reflection.Emit (Fun!), but the other problems encountered were:

  • A lot of the methods on Controller are actually useful, and I ended up having to use T4 to generate a wrapper around some sort of (optional) ActionContainer base class to call into these.
  • If you're trying to maintain code that can easily be ported from a default MS MVC application then you need to copy all the attributes across from an action method to the generated controller
  • Even if you don't use the attributes and find a different way of expressing action modifiers, they still need writing out to the generated controller because that is how MS MVC works.

Even if we used MEF to do the work of compositing the controllers, we would still have the problem that we were trying to impose a manner of working to the MS MVC framework that the MS MVC framework is not really geared up to do! (in my opinion).

Summary

In summary, the way MvcEx does things was a bad decision, and I'll probably change it for the method the previous blog entry uses in the near future (Simply choosing the controller we want to use).

Although it's not ideal in so far as it doesn't solve the problems we have with the design of MS MVC,  if we go down the route of trying to hide our flawed framework with a load of abstractions (MVC Turbine etc), we end up in a situation where we might have been better off writing our own MVC framework or using something else more suited to the kind of applications we want to build. (Fubu MVC, Open Rasta, etc)

It is of course probably worth contributing to that particular discussion at the asp.net uservoice thread, as our best hope is that the MS MVC guys take note of the multi-tenancy discussion and give some love to the framework in that area.

Coming up...

With the blogging started up once more, I'll be continuing this series by delving into a few questions I've had on the subject of multi-tenancy regarding configuration, deployment, internalisation and a few other hurdles we've had to cross whilst building our multi-tenant software on top of MS MVC.




   


Print | posted on Monday, April 05, 2010 2:46 PM

Feedback

# re: Multi-tenancy in ASP.NET MVC - Controller Actions (Part II)

Left by Gareth Mark Elms at 8/28/2010 3:50 PM
Gravatar Love this series it's helping me to understand Orchard CMS so thanks for sharing. Do you stand by the MvcEx project as is? Noticed it hasn't been updated since January

# re: Multi-tenancy in ASP.NET MVC - Controller Actions (Part II)

Left by robashton at 8/28/2010 4:13 PM
Gravatar "Stand by it", we use it in our product at work, but I still just consider it to be a reference implementation of one way you could do pluggable controllers.

It was a little bit too "pure" IMO, and an implementation where you simply "chose" which controller to use instead of crap loads of reflection would be a little more pragmatic :)

I'm done with MS MVC for the longterm though, rather than move to MVC2/MVC3, when we upgrade, we'll be switching to Fubu, which will allow us to do a lot of this kind of thing out of the box.

Your comment:





 
Please add 2 and 8 and type the answer here:

Copyright © Rob Ashton

Design by Rob Ashton, Based On A Design By Bartosz Brzezinski