<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>ASP.NET MVC</title>
        <link>http://codeofrob.com/category/8.aspx</link>
        <description>ASP.NET MVC</description>
        <language>en-GB</language>
        <copyright>Rob Ashton</copyright>
        <generator>Subtext Version 2.1.2.2</generator>
        <item>
            <title>Multi-tenancy in ASP.NET MVC - Controller Actions (Part I)</title>
            <link>http://blog.codeofrob.com/archive/2010/02/14/multi-tenancy-in-asp.net-mvc-controller-actions-part-i.aspx</link>
            <description>&lt;p&gt;&lt;strong&gt;Previous entries in the series&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://codeofrob.com/archive/2010/02/01/multi-tenancy-in-asp.net-mvc-why-do-we-want-to.aspx"&gt;Why we want it&lt;/a&gt; &lt;/li&gt;
    &lt;li&gt;&lt;a href="http://codeofrob.com/archive/2010/02/04/multi-tenancy-in-asp.net-mvc-breaking-it-down.aspx"&gt;Breaking it down + Themes&lt;/a&gt; &lt;/li&gt;
    &lt;li&gt;&lt;a href="http://codeofrob.com/archive/2010/02/08/multi-tenancy-in-asp.net-mvc-views.aspx"&gt;Views&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;font face="Arial"&gt;In the last entry, we covered how and why we might want to replace existing views and partial views from the core application with our own from modules. We also covered that with this ability it was possible to add entirely new views and partial views.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;However, views need actions and actions come from controllers. If we add a new view to the application and the core application does not support that path with an action, that view cannot be loaded.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It stands to reason therefore that our modules need the ability to add new controller actions (and indeed replace existing actions) at run-time on a per-request basis - again assuming we're going for full on multi-tenancy.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Actions come from controllers, and by default controllers come from the main web assembly. Now obviously our modules should be as self contained as possible and therefore probably each have their own assemblies so they can be developed separately and added to the project ad-hoc.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Once again, the ASP.NET MVC team have given us an extensibility point with which to override this default behaviour with the ability to implement our own controller factories.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Resolving actions&lt;/strong&gt;&lt;br /&gt;
As with the last topic, I will assume the presence of a configuration provider that can tell us which modules are loaded.&lt;br /&gt;
For purposes of simplicity, the Module class now contains a reference to an Assembly that we'll assume was loaded in when the configuration was last scanned.&lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class Module
    {
        public string Id
        {
            get;
            set;
        }

        public Assembly Assembly
        {
            get;
            set;
        }
    }
&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The job of the ControllerFactory is another well documented concept; when a controller is required, the factory is invoked with the name of the controller being requested and the current request data. It is expected to return an instance of the controller (which is used for that single request), and then just like the ViewEngine is given that controller to dispose of at the end of the request.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The simplest solution is clearly going to be that we look at the context we have access to and then work out which controller to return based on that context.&lt;br /&gt;
The context in this case being the name of the controller, the action being requested and the collection of modules which are currently active for this request.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Each module can therefore hold their own controllers with their own actions, and the controller factory can select which controller to return when a specific action is being invoked.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I implement my controller factory from the base interface, which is System.Web.Mvc.IControllerFactory:&lt;/font&gt; &lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class ModuleControllerFactory : IControllerFactory
    {
        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            throw new NotImplementedException();
        }

        public void ReleaseController(IController controller)
        {
            throw new NotImplementedException();
        }
    }
&lt;/pre&gt;
&lt;p&gt;ReleaseController can just check for IDisposable and dispose if necessary, so we'll take that as read and focus on what we need to do in order to create the controller.&lt;/p&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;strong&gt;
&lt;h3&gt;&lt;font face="Arial"&gt;&lt;strong&gt;The Goal&lt;/strong&gt;&lt;/font&gt;&lt;/h3&gt;
&lt;/strong&gt;&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;These are the modules exposed by the application, the controllers they provide and the actions those controllers have on them.&lt;/font&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;CoreModule&lt;/font&gt;
    &lt;ul&gt;
        &lt;li&gt;&lt;font face="Arial"&gt;HomeController&lt;/font&gt; &lt;/li&gt;
        &lt;li&gt;&lt;font face="Arial"&gt;ActionResult Index();&lt;/font&gt; &lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;ModuleOne&lt;/font&gt;
    &lt;ul&gt;
        &lt;li&gt;&lt;font face="Arial"&gt;HomeController&lt;/font&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;font face="Arial"&gt;ActionResult Extra();&lt;/font&gt; &lt;/li&gt;
        &lt;/ul&gt;
        &lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;ModuleTwo&lt;/font&gt;
    &lt;ul&gt;
        &lt;li&gt;&lt;font face="Arial"&gt;HomeController&lt;/font&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;font face="Arial"&gt;ActionResult Index();&lt;/font&gt; &lt;/li&gt;
            &lt;li&gt;&lt;font face="Arial"&gt;ActionResult Extra();&lt;/font&gt; &lt;/li&gt;
        &lt;/ul&gt;
        &lt;/li&gt;
        &lt;li&gt;&lt;font face="Arial"&gt;OtherController&lt;/font&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;font face="Arial"&gt;ActionResult Index(); &lt;/font&gt;&lt;/li&gt;
        &lt;/ul&gt;
        &lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; WIth the set-up, the following behaviour is desired:&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Core Module loaded:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;/Home/Index requested =&amp;gt; CoreModule Index Invoked&lt;br /&gt;
/Home/Extra requested =&amp;gt;  Action Not found&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Core + ModuleOne Loaded&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;/Home/Index requested =&amp;gt; CoreModule Index Invoked&lt;br /&gt;
/Home/Extra requested =&amp;gt;  ModuleOne Extra Invoked&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Core + ModuleOne + ModuleTwo Loaded (in that order)&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;/Home/Index requested =&amp;gt; ModuleTwo Index Invoked&lt;br /&gt;
/Home/Extra requested =&amp;gt; ModuleTwo Extra Invoked&lt;br /&gt;
/Other/Index requested =&amp;gt; ModuleTwo Index Invoked&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;h3&gt;&lt;font face="Arial"&gt;A Solution&lt;/font&gt;&lt;/h3&gt;
&lt;p&gt;This is actually quite tricky, as the solution is going to involve not only scanning for the controllers, but scanning for methods on those controllers that match the actions being requested.&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;There are a lot of rules involved already in MVC selecting the right method to call from a controller, and we don't want to go down the route of duplicating this, so this is where we set a convention and say that if *any* action is found with the name being requested, that we'll use that controller and assume that all the necessary permutations of that action will be provided too. (A post action vs Get action for example).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;There are two parts to solving this problem, finding the type we want to create, and creating the controller from that type.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The process will be similar to that of the ViewEngine example:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;1) Reverse the module list order so we have the most recently loaded first&lt;br /&gt;
2) Scan all the types in the assembly for that module&lt;br /&gt;
3) Find a type with the name we're looking for ( &amp;lt;Name&amp;gt;Controller )&lt;br /&gt;
4) Scan the methods on that type to find the action we're looking for&lt;br /&gt;
5) If found, return this type&lt;br /&gt;
6) Else Continue&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Obviously reflecting on all these types is a slow process, and we should cache the type once found by configuration id, controller name and action name. &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Here is some code which loosely achieves the above:&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;private Type FindControllerType(String controllerName, RequestContext requestContext, Configuration currentConfiguration)
        {
            // Generate the type name we're looking for
            String controllerTypeName = string.Format("{0}Controller", controllerName);

            // Get the action and therefore method name we're looking for
            String actionName = (string)requestContext.RouteData.Values["action"];

            // TODO: Check Cache here

            // Get modules in reverse order
            var searchModules = currentConfiguration
                .Modules
                .Reverse();

            foreach (var module in searchModules)
            {
                // Get all the types in the assembly
                Type[] controllerTypes = module.Assembly.GetTypes()
                    .Where(
                        t =&amp;gt;
                            // Where the type name is the one we're looking for
                            t.Name == controllerTypeName &amp;amp;&amp;amp;

                            // Where it can be cast to a controller
                            typeof(IController).IsAssignableFrom(t) &amp;amp;&amp;amp;

                            // And there is a public instance method with the name we're looking for on that type
                            t.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
                            .Where(m =&amp;gt; m.Name == actionName).Count() &amp;gt; 0

                        ).ToArray();

                // Skip to the next module if no types found
                if (controllerTypes.Length == 0) { continue; }

                // Else, simply return the first one found
                return controllerTypes[0];
            }

            // Fail
            return null;
        }
&lt;/pre&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;br /&gt;
A very rudimentary controller factory implementation would therefore look something like this:&lt;br /&gt;
&lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt; public class ModuleControllerFactory : IControllerFactory
    {
        private IConfigurationProvider mConfigurationProvider;

        public ModuleControllerFactory(IConfigurationProvider configurationProvider)
        {
            mConfigurationProvider = configurationProvider;
        }

        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            Type t = FindControllerType(controllerName, requestContext, mConfigurationProvider.GetActiveConfiguration());
            return (IController)Activator.CreateInstance(t);
        }

        public void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
// Etc
&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It is of course probably desirable to instantiate the controller using your favourite IOC container  - so for StructureMap for example instead of using Activator.CreateInstance you would call ObjectFactory.GetInstance(t);&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;(Actually, you'd probably inject the container as well rather than calling ObjectFactory directly but you get the gist).&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;
&lt;h3&gt;&lt;font face="Arial"&gt;Summary&lt;/font&gt;&lt;/h3&gt;
&lt;p&gt;Essentially, we can completely re-wire this part of the ASP.NET MVC framework to do what we want it to do. We can load our controllers from wherever based on whatever context we like - and this gives us a powerful mechanism for pluggability and therefore multi-tenancy.&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I did contemplate trying to achieve this through routing - custom routing constraints and handlers - but it's not a tidy solution, it generally means having different names for your controllers, or playing havok with namespaces and configuration and because a lot of that configuration is static it often involves re-compilation.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Re-compilation is something to be avoided, as we ideally want to be able to add new customers by just modifying configuration.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Anyway, there are a number of options and this is just one of them,  I'll be hoping to cover a crazy solution using Reflection.Emit and hopefully delve into MEF before I'm done with this particular part of the multi-tenancy story.&lt;/font&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;img src="http://blog.codeofrob.com/aggbug/15.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/02/14/multi-tenancy-in-asp.net-mvc-controller-actions-part-i.aspx</guid>
            <pubDate>Sun, 14 Feb 2010 17:17:29 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/15.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/02/14/multi-tenancy-in-asp.net-mvc-controller-actions-part-i.aspx#feedback</comments>
            <slash:comments>12</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/15.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/15.aspx</trackback:ping>
        </item>
        <item>
            <title>Multi-tenancy in ASP.NET MVC - Views</title>
            <link>http://blog.codeofrob.com/archive/2010/02/08/multi-tenancy-in-asp.net-mvc-views.aspx</link>
            <description>&lt;p&gt;&lt;strong&gt;Previous entries in the series&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://codeofrob.com/archive/2010/02/01/multi-tenancy-in-asp.net-mvc-why-do-we-want-to.aspx"&gt;Why we want it&lt;/a&gt; &lt;/li&gt;
    &lt;li&gt;&lt;a href="http://codeofrob.com/archive/2010/02/04/multi-tenancy-in-asp.net-mvc-breaking-it-down.aspx"&gt;Breaking it down + Themes&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;font face="Arial"&gt;One of the requirements of our multi-tenant application, is having the ability to replace or add new pages (or parts of pages) in the system for each of our modules.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;While a customer may ask for an entirely new 'area' on the site (MVC2 covers this), the chances are they just want the addition of a single page or replacement of what is already provided in the stock product.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The obvious port of call for change of this kind are the views and partial views situated within the web application, and finding a way to add or override these on a per-module basis.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;Throughout the following entry I'll assume we have access to a configuration provider that looks something like this:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;public interface IConfigurationProvider
{
    Configuration GetActiveConfiguration();
}&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Where Configuration has the following simplistic structure (for demo purposes)&lt;/font&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class Configuration
    {
        public string Theme
        {
            get;
            set;
        }

        public Module[] Modules
        {
            get;
            set;
        }
    }

    public class Module
    {
        public string Id
        {
            get;
            set;
        }
    }&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In other words, we have a way of querying for the 'currently active configuration' (remember, our active configuration is per-request because we're attempting true multi-tenancy), and our configuration consists of a single theme and a list of loaded modules.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Each module has an Id and we'll use this to infer a number of things by convention. (Again, this is just a demo, and you can do this&lt;em&gt; however you like&lt;/em&gt;.)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;br /&gt;
&lt;font face="Arial"&gt;I assume each module will provide a collection of views and partial views, and if a module is loaded *after* another module, and provides another view or partial view with the same name and path, it will replace the previously loaded view or partial view.&lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;&lt;p&gt;&lt;font face="Arial"&gt;I was asked in a comment on a previous entry what my folder structure looked like,  and this is where the folder structure starts to become important.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Collapsed views" src="http://fear.the.codeofrob.com/mt_views/views_collapsed.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Every module's views come packaged in a single directory,  with another directory called Views inside of it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Underneath each of these Views directories, is the same folder structure you'd expect from a traditional ASP.NET MVC Website, with a directory per controller and a collection of views and partial views.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This means that both Core and ModuleOne can contribute or replace views for the  actions from the "Home" Controller.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;A thing of note, is that the web.config file that would ordinarily live in the Views directory in a traditional ASP.NET MVC application has been moved out into the Site directory above all the module directories - as this does things like give you Intellisense in your views (if I recall correctly) as well as actually facilitating the functionality in the ASP.NET MVC Framework.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Expanded, our project looks like this:&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Expanded folder selection" src="http://fear.the.codeofrob.com/mt_views/views_expanded.png" /&gt;&lt;br /&gt;
 &lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Assuming the partial view "Widget" is exposed somewhere on the Index page, the following desired scenarios present themselves:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Core Module loaded:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;/Home/Index requested =&amp;gt; Index served from CoreModule, with Widget from CoreModule&lt;br /&gt;
/Home/Extra requested =&amp;gt; Page not found&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Core + ModuleOne Loaded (in that order)&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;/Home/Index requested =&amp;gt; Index served from CoreModule with Widget from ModuleOne&lt;br /&gt;
/Home/Extra requested =&amp;gt; Extra served from ModuleOne&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;ModuleOne + Core Loaded (in that order)&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;/Home/Index requested =&amp;gt; Index served from CoreModule with Widget from CoreModule&lt;br /&gt;
/Home/Extra requested =&amp;gt; Extra served from ModuleOne&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;
&lt;h3&gt;&lt;font face="Arial"&gt;Enter the View Engine&lt;/font&gt;&lt;/h3&gt;
&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is all very well and good as our requirements are quite clear, but the next step is making the above happen!&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;ASP.NET MVC provides the facility to override the View Engine, which is the component that determines how views are rendered.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This can be used to simply load views in from a different location, or even to allow completely bespoke mark-up to be transformed into HTML (Ala the &lt;a href="http://sparkviewengine.com"&gt;Spark View Engine&lt;/a&gt;).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;By default, the framework will use System.Web.Mvc.WebFormViewEngine, which is what loads the views from the View directory using the default convention and returns a ViewEngineResult containing a WebFormView which eventually ends up being used to render out the view.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The WebFormViewEngine class itself is extendable, and by inheriting from it we can change the search paths it uses to locate the views and partial views.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Naturally this is the first place we look to solve our problem, as writing less code is always preferable if we can get away with it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The set-up of WebFormViewEngine is that in the constructor we  can give it a selection of search paths - which means for the life-time of WebFormViewEngine those search paths are set.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;They can be modified per-request, but WebFormViewEngine inherits from VirtualPathProviderViewEngine which caches paths under which it has found files (or at least, reading the source it looks like it does!).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;For performance purposes (per-configuration path caching), it would probably therefore be best implementing a ViewEngine from scratch, but as the main body of work is achieved through the return result of the  view engine methods, this is not as daunting an experience as we might think.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is what IViewEngine looks like when we first create it:&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class ModuleViewEngine : IViewEngine
    {
        public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            throw new NotImplementedException();
        }

        public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            throw new NotImplementedException();
        }

        public void ReleaseView(ControllerContext controllerContext, IView view)
        {
            throw new NotImplementedException();
        }
    }&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;First things first, ReleaseView doesn't need to do anything unless the views you return implement IDisposable, and for that the following code can be used.&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial" /&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        public void ReleaseView(ControllerContext controllerContext, IView view)
        {
            IDisposable disposable = view as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The next thing of note is that the searching logic for locating the files is the same regardless of whether the engine is looking for a view or partial view, so we can create the following method and forget about it for now:&lt;/font&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        private string ResolvePath(String requestedFile, ControllerContext controllerContext)
        {
            throw new NotImplementedException();
        }&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;FindPartialView and FindView both return the same type, and with similar values - I won't go into detail because the procedure is well documented elsewhere, but my methods in this example look like this:&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial" /&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            String foundFile = ResolvePath(string.Format("{0}.ascx", partialViewName), controllerContext);

            return new ViewEngineResult(
                new WebFormView(foundFile),
                this
            );       
        }

        public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            String foundFile = ResolvePath(string.Format("{0}.aspx", viewName), controllerContext);

            return new ViewEngineResult(
                 new WebFormView(
                     foundFile,
                     masterName),
                 this);
        }&lt;/pre&gt;
&lt;p class="brush: csharp;" title="code"&gt; &lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Note:&lt;/strong&gt; This example will not deal with absolute paths being specified, it will also not deal gracefully with the file not being found at all - this simply involves returning a list of the searched locations on failure and isn't worth discussing further here.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;ResolvePath is entirely dependent on the logic you want to follow when searching for your per configuration module provided views, but a reference implementation might look like the following:&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        private string ResolvePath(String requestedFile, ControllerContext controllerContext)
        {
            String result = string.Empty;

            // Reverse the module order so we search from most recently ordered first
            var searchModules = mConfigurationProvider
                .GetActiveConfiguration()
                .Modules
                .Reverse()
                .Select(m =&amp;gt; m.Id);

            // Search through each module in turn
            foreach (String module in searchModules)
            {
                // Try the controller specific view folder first
                String controllerName = controllerContext.RouteData.Values["controller"] as string;
                result = GetFilename(requestedFile, controllerContext, module, controllerName);
                if (string.IsNullOrEmpty(result))
                {
                    result = GetFilename(requestedFile, controllerContext, module, "Shared");
                }
                if (!String.IsNullOrEmpty(result)) { return result; }
            }

            // Error!
            return null;
        }

        private string GetFilename(String requestedFile, ControllerContext controllerContext, String module, String controllerName)
        {
            String path = string.Format("~/Views/{0}/{1}/{2}/", module, controllerName, requestedFile);
            String filename = controllerContext.HttpContext.Server.MapPath(path);
            if (File.Exists(filename)) { return path; }
            return null;
        }&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Where mConfurationProvider is the IConfigurationProvider mentioned earlier.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In this implementation, we reverse the order of the loaded modules to get the most recently loaded first, and then select just the module id.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;That gives us a list of folders names to search through in order to find the view, first attempting to find the file within the folder for the current action, and then the shared directory (just like the default WebFormViewEngine).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;If it's not found, we return null and cross our fingers and hope for the best.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Just to re-iterate, in the real world you need to add error handling for when a view is not located, and code to deal with absolute paths (although maybe you don't support them and don't need to write that code!).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Because we have the current configuration, we can perform the caching of file locations on a per-configuration basis - just remember to disable caching during testing and debugging!&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial" /&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;h3&gt;&lt;font face="Arial"&gt;Summary&lt;/font&gt;&lt;/h3&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I haven't gone into a lot of detail about the implementation of the view engine because it's beyond the scope of this blog entry - a lot of information about writing custom view engines can be found with a "Bing" (or Google search *cough*) and it was not my intention of repeating them.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;What we have covered is how we might utilise the power of view engines and a set of folder conventions to allow modules to create/override views and partial views. &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;As with all of these entries, the actual implementation is up to you and your particular product needs and the code examples should not be taken as gospel.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Next entry we'll be getting even more technical and covering how we can allow the modules to provide actions for these added views - and even how to override controller actions that have already been defined in other modules.&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;&lt;font face="Arial" /&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;Examples of this code can be found in the DDD8 code samples &lt;a href="http://codeofrob.com/archive/2010/01/31/ddd8-post-event.aspx "&gt;here&lt;/a&gt;.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;
&lt;/font&gt;&lt;img src="http://blog.codeofrob.com/aggbug/13.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/02/08/multi-tenancy-in-asp.net-mvc-views.aspx</guid>
            <pubDate>Mon, 08 Feb 2010 21:19:30 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/13.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/02/08/multi-tenancy-in-asp.net-mvc-views.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/13.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/13.aspx</trackback:ping>
        </item>
        <item>
            <title>Multi-tenancy in ASP.NET MVC - DDD8 Video</title>
            <link>http://blog.codeofrob.com/archive/2010/02/05/multi-tenancy-in-asp.net-mvc-ddd8-video.aspx</link>
            <description>&lt;p&gt;The video is now up of my talk at DDD8, I've reviewed it and determined that while it's a bit fast ("Like listening to a podcast at double speed" according to &lt;a href="http://twitter.com/lukesmith"&gt;@lukesmith&lt;/a&gt;) it's not too embarrassing.&lt;/p&gt;

&lt;p&gt;Unfortunately the audio gets a bit out of sync towards the code, so you'll have to use your imagination until what I'm talking about shows up ;-)&lt;/p&gt;

&lt;object width="400" height="300"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=9217399&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=9217399&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300" /&gt;&lt;/object&gt;&lt;p&gt;&lt;a href="http://vimeo.com/9217399"&gt;Multi-tenant ASP.NET MVC Projects (Or 30 very different customers and a single codebase) - Rob Ashton - DeveloperDeveloperDevel&lt;/a&gt; from &lt;a href="http://vimeo.com/user3077884"&gt;Phil Winstanley&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blog.codeofrob.com/aggbug/12.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/02/05/multi-tenancy-in-asp.net-mvc-ddd8-video.aspx</guid>
            <pubDate>Fri, 05 Feb 2010 09:52:17 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/12.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/02/05/multi-tenancy-in-asp.net-mvc-ddd8-video.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/12.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/12.aspx</trackback:ping>
        </item>
        <item>
            <title>Multi-tenancy in ASP.NET MVC - Breaking it down</title>
            <link>http://blog.codeofrob.com/archive/2010/02/04/multi-tenancy-in-asp.net-mvc-breaking-it-down.aspx</link>
            <description>&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Previous entries in the series&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://codeofrob.com/archive/2010/02/01/multi-tenancy-in-asp.net-mvc-why-do-we-want-to.aspx"&gt;Why do we want multi-tenancy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In the last entry, we covered the basics of what I consider multi-tenancy to be, and why we might perhaps want to write our ASP.NET MVC web application with multi-tenancy in mind.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The "ASP.NET MVC" component (or front-end) of your multi-tenant application probably only covers a small fraction of your entire codebase but is also the first and often only contact your customer has with your application, so ends up being their first point of call when asking for changes to your system. &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It also ends up being the most awkward part of to change because that's the nature of using a framework like ASP.NET MVC which is designed primarily to be used in single-tenant scenarios.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Before getting into the technical details of how I implement a multi-tenant app in this environment, it's worth covering the components of our chosen framework and establishing where to start.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: This will not be an overly technical post,  and I apologise to those that want me to just jump right in and start talking code.  This will be the last introductory post in the series - promise :)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Getting to the point,  this is how I personally split up the MVC application concepts into themes and modules.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;table border="1" cellspacing="1" summary="" cellpadding="1" width="400"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;strong&gt;Themes&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;Modules&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;CSS&lt;/td&gt;
            &lt;td&gt;Views&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Theme-specific images&lt;/td&gt;
            &lt;td&gt;Partial Views&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Theme-specific JavaScript&lt;/td&gt;
            &lt;td&gt;Controller actions&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Master pages&lt;/td&gt;
            &lt;td&gt;Module-specific JavaScript&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Whether we like it or not, designers like to deploy JavaScript alongside their designs these days, most notably with libraries such as &lt;a href="http://www.emblematiq.com/lab/niceforms/ "&gt;Niceforms&lt;/a&gt; and its associated brethren. &lt;br /&gt;
It therefore pays to  make the distinction between functional and theme-specific JavaScript and allow both modules and themes to provide their own collections of scripts.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;For shared libraries like jQuery etc, they can be made available as part of the core application, and modules and themes can take it for granted that it will be available for their use.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;/font&gt;&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Most theming can be achieved by switching style sheets if the mark-up has been designed properly and this is an obvious candidate for theming support. Switching between style sheets is a trivial and well documented operation and can easily be achieved through the use of a HtmlHelper extension method.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I'll assume I don't need to write an entry on achieving the switching between either the CSS or JavaScript, although as with anything if prompted I'll cover the subject.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Master Pages&lt;/strong&gt;&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Sometimes the client wishes for major structural changes to the web application, and CSS changes may not be enough. For this we have master pages although because of the increased cost of having to maintain the extra mark-up  they should probably only be used as a last resort.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I wrote a blog entry about the various methods of &lt;a href="http://codeofrob.com/archive/2009/11/01/dynamically-switching-between-master-pages-in-asp.net-mvc.aspx"&gt;switching between the master pages at runtime&lt;/a&gt; a while ago so I won't be covering that again.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;For my purposes over the coming posts, I assume that the structure of the master page IS a part of theming, and that we are using sub-master pages and separate child master pages across the site for different interfaces. I therefore use the OnPreInit method mentioned in the above entry for the greatest amount of flexibility.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Views + Partial Views&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;New modules will require  either new views or the ability to override existing views, and thus I consider views to be a functional aspect of the application.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I have seen views and partial views used for theming in frameworks or products where actual functional module support was highly limited. I assume a multi-tenant system *does* have decent functional module support and thus they are part of modules and not theming.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Mark-up in the views should simply be kept as theme-agnostic as possible, as themes won't be able to change it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I'll be covering this in this series, utilising  the power of a custom view engine to find and replace views based on the currently active modules.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller Actions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;These are obviously an important part of adding functionality to the application through the use of modules.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Because we have the ability to not only add new  views, but to modify them - we also need the ability to add new actions and indeed replace existing actions (as modified views may accept modified view models!)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is probably the hardest problem to solve and there are a few ways of solving it,  this too will be coming in this series - using custom controller factories to compose or locate controllers dynamically based on the currently active modules.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;strong&gt;In Summary&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;We have covered the components of an MVC web application and established where the boundaries lie between modules and theming support.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In the next entry I'll be covering how to utilise view engines to achieve the per-module views and partial views.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
 &lt;/p&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;&lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://blog.codeofrob.com/aggbug/11.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/02/04/multi-tenancy-in-asp.net-mvc-breaking-it-down.aspx</guid>
            <pubDate>Thu, 04 Feb 2010 23:19:40 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/11.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/02/04/multi-tenancy-in-asp.net-mvc-breaking-it-down.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/11.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/11.aspx</trackback:ping>
        </item>
        <item>
            <title>Multi-tenancy in ASP.NET MVC - Why do we want it?</title>
            <link>http://blog.codeofrob.com/archive/2010/02/01/multi-tenancy-in-asp.net-mvc-why-do-we-want-to.aspx</link>
            <description>&lt;p&gt;&lt;font face="Arial"&gt;I'll be gratuitously "borrowing" a lot  of material from my DDD8 slides in this post, it seemed like the right thing to do given that this series is a write-up and then continuation of that talk.&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;When dealing with more than one customer in the desktop market, it is customary to have a single product which is extendable through the use of plug-ins and an API, and often you can leave it up to your consumer base to write those plug-ins and add to your product in a manner they see fit.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In the web world it's a bit different, and you don't typically get that kind of behaviour (Facebook applications may or may not count, depending on how you look at it).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;br /&gt;
In a simple world, you'll have a single product which is used directly off the shelf by multiple customers:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Single product" src="http://fear.the.codeofrob.com/mt_why/single_product.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;When building web applications for a varied and paying customer base, It is likely that you have customers that are fickle and will want things done their way. &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It often does not make business sense to turn good business down, and the business is what pays the hungry developer and thus when you finally get a customer who wants things done differently,  the business tells the developer to jump and the business's required response is the proverbial "how high?".&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Consider the above diagram then, and imagine Customer A asking for something 'just a little bit different' and think about what your options could be.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;We'll get the obvious dusted out of the way first:&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="if( featureIsEnabled....)" src="http://fear.the.codeofrob.com/mt_why/feature_code.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;When I switched to the above code as a slide in my multi-tenant talk, I was greeted with laughter, but we've all known products which have ended up with such delightful nuggets in them. &lt;br /&gt;
It's blindingly obvious that it's not the right solution, and that as you progress down the route of making further modifications for either Customer A, B or C you'll end up with an un-maintainable mess of switches and flags. 'Nuff said.&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;You could then decide that you're going to keep that customer as a new product in its own right - that would remove the need for all those on-off switches.&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;img alt="A bespoke copy" src="http://fear.the.codeofrob.com/mt_why/bespoke_copy.png" /&gt;&lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;This should very obviously be a big no-no as maintaining that then bespoke product and keeping it up to date with any changes then made to your core product is going to be nothing more than a giant headache. &lt;br /&gt;
As you get more customers, the number of developers you'll need to hire will increase almost in direct proportion to the number of codebases you have to maintain!  (Again, I've seen this done - so don't think I'm just pointing out the obvious for the sake of it)&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Let's move onto the more-often used approach, of branching from a base product for your different needs, and utilising the power of a source control system to keep changes in sync between your code-bases.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;img alt="Branching as an alternative" src="http://fear.the.codeofrob.com/mt_why/bespoke_branch.png" /&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Customer A can be kept up to date by merging changes from the core product, and Customer B/C can get additional features from Customer A's branch if and when they desire it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;At first glances, it seems like this solution fits our needs - and indeed it can work well in a lot of given  scenarios. The problem comes when you scale this solution up to more than this small example - as few of us are (un)lucky enough to be able to deal with only three customers and remain financially viable!&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Here is a small example of 30 customers sharing 15 code-bases!&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;img alt="A mess of branching dependencies" src="http://fear.the.codeofrob.com/mt_why/bespoke_mess.png" /&gt;&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Yowsers! &lt;br /&gt;
How do you keep track of who has what features? &lt;br /&gt;
How do you test all of those different branches of code? &lt;br /&gt;
How do you deploy those branches of code?&lt;br /&gt;
How do you make a new version of the product and serve it to a customer?&lt;br /&gt;
How many developers do you need to manage that process?&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It's never as simple as it looks, and you end up with not only the above problems, but you end up with the additional problems of what happens when a branch becomes radically different and you're unable to merge changes around.&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;There is too much developer interaction here - and your skilled staff end up having to spend most of their time creating new branches/pushing changes around instead of spending their time doing what they're actually trained to do - writing code. &lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;br /&gt;
Adding a new customer shouldn't be about changing code, it should be about manipulating configuration, and modifying a customer shouldn't be about changing code, it should also be about manipulating configuration. &lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In other words, problems should only be solved once - and configuration should be used to give or take features to and from customers.&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;&lt;font face="Arial" /&gt;&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;strong&gt;
&lt;h3&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;strong&gt;Enter multi-tenancy...&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/h3&gt;
&lt;/strong&gt;&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The core concept of a well written multi-tenant application is that you should have a single code base, and a number of configurations - where each configuration tells the runtime what functionality should be available and what the look/feel should be.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Before continuing, I'd like to define a few of the terms I'll be using throughout this series of blog entries.&lt;/font&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;Module: A discrete set of functionality&lt;/font&gt; &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;Theme: The look and feel&lt;/font&gt; &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;Configuration:  A selection of modules, and a single theme&lt;/font&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is a personal leaning, and I know that some people would set this up differently. Each to their own, we've got to draw lines somewhere!&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;br /&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;Anyway - as far as I'm concerned, Multi-tenancy gives us some of the following benefits:&lt;/font&gt; &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Deployment becomes a simple case of installing your application onto a server, and setting up the configurations for that application.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;When a request comes in, context is determined by some means (auth credentials, the hostname, whatever), and the relevant configuration is selected from that context. &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;img alt="A single server serving multiple customers" src="http://fear.the.codeofrob.com/mt_why/multi_tenant_single.png" /&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;This is a very simple way of working, and if you design your application correctly, it becomes obvious that your hosting/maintenance costs can be reduced.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;You can have multiple servers with the exact same codebase installed on them, and with all the configurations available to them (In other words, identical).  Scaling up becomes a simple matter of adding more of those identical servers - and if you're really smart you can load balance across your VPSs and power them up/down as required. &lt;br /&gt;
You no longer need to worry (too much) about the fact that you have all of those customers, and you can concentrate on the health of your system as a whole.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Load balanced multi-tenant system" src="http://fear.the.codeofrob.com/mt_why/multi_tenant_balanced.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
 Some more benefits:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;You add a feature once, and deploy it to your customers through the use of configuration&lt;/font&gt; &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;You can fix a bug, and deploy the fix once &lt;/font&gt; &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt; Potentially easy management of your infrastructure (This actually comes through good design, and multi-tenancy just aids in that goal)&lt;/font&gt; &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;Developers get to spend their time coding new features/fixing bugs&lt;/font&gt; &lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;New customers can have a site created in minutes and start to give feedback immediately&lt;/font&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Everybody is a winner and we all get to go home and have pie and punch.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In the next entry, things will hot up as I'll start to look at ASP.NET MVC and determine the components that we can use to aid us in creating a multi-tenant application.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;/font&gt;&lt;/font&gt;
&lt;p&gt; &lt;/p&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;img src="http://blog.codeofrob.com/aggbug/10.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/02/01/multi-tenancy-in-asp.net-mvc-why-do-we-want-to.aspx</guid>
            <pubDate>Mon, 01 Feb 2010 22:10:22 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/10.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/02/01/multi-tenancy-in-asp.net-mvc-why-do-we-want-to.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/10.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/10.aspx</trackback:ping>
        </item>
        <item>
            <title>Multi-tenancy and ASP.NET MVC</title>
            <link>http://blog.codeofrob.com/archive/2010/01/31/multi-tenancy-and-asp.net-mvc.aspx</link>
            <description>&lt;p&gt;&lt;font face="Arial"&gt;I spoke about this chestnut briefly at DDD8, and I want to start expanding on the subject.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;My plan is over the next few weeks to start talking more about multi-tenancy in our web-apps, and to get everybody else doing the same - speaking to other developers after my talk I realised that we're not alone, people are working on solutions but they're just not talking about it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;By getting some dialogue going, I hope we can generate a public description of what is good and what is bad about attempting to build multi-tenant applications on top of ASP.NET MVC, and what our possible avenues of achieving this can be.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The suggested topics I aim to cover in this series of blog entries will (to begin with) be somewhere along these lines: (As I've already written most of the material!)&lt;/font&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;What is multi-tenancy and why do we want it?&lt;/font&gt;&lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;The building blocks of a multi-tenant application in ASP.NET MVC&lt;/font&gt;&lt;/li&gt;
    &lt;font face="Arial"&gt;
    &lt;li&gt;How I integrated MvcEx into NerdDinner to give it some multi-tenant capabilities&lt;/li&gt;
    &lt;/font&gt;&lt;/ul&gt;
    &lt;p&gt;If there is anything else you think I should cover as part of this series, then let me know by either Twitter or the comments field below.&lt;/p&gt;
    &lt;p&gt;&lt;font face="Arial"&gt;I am loathe to go into detail on what I consider to be the other 90% of the multi-tenancy story - your domain, the rest of your codebase, managing your databases/configurations etc, as you can get all of that information from people who are far more versed in the subject than I.&lt;/font&gt;&lt;/p&gt;
    &lt;p&gt;&lt;font face="Arial"&gt;But, if pushed on a particular subject I guess I will describe how I deal with those issues in the codebases I have control over, and you'll have to take it (as you should take anything written on these pages) with a pinch of salt.&lt;br /&gt;
    &lt;/font&gt;&lt;/p&gt;
    &lt;/font&gt;&lt;img src="http://blog.codeofrob.com/aggbug/9.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/01/31/multi-tenancy-and-asp.net-mvc.aspx</guid>
            <pubDate>Sun, 31 Jan 2010 20:16:24 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/9.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/01/31/multi-tenancy-and-asp.net-mvc.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/9.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/9.aspx</trackback:ping>
        </item>
        <item>
            <title>DDD8 - Post Event</title>
            <link>http://blog.codeofrob.com/archive/2010/01/31/ddd8-post-event.aspx</link>
            <description>&lt;p&gt;Wow.&lt;/p&gt;
&lt;p&gt;That was a wonderful day, and the sessions I ended up going to were:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;@ICooper's session on MVC Architecture (preaching the choir but good to be re-assured) &lt;/li&gt;
    &lt;li&gt;@robashton's session on Multi-tenant ASP.NET MVC (obviously) &lt;/li&gt;
    &lt;li&gt;@holytshirt's session on Mono (Good to see this project is advancing well) &lt;/li&gt;
    &lt;li&gt;@garyshort's session on JClosure (Lovely!) &lt;/li&gt;
    &lt;li&gt;@blowdart's session on the crystal maze &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last session was interrupted constantly by the MVPs and associated crowd because Barry is leaving the UK and heading off to MS to learn how to spell :)&lt;/p&gt;
&lt;p&gt;There isn't much specifically to talk about really, it's been said by everybody. The event was well organised, the post-event meal was also surprisingly kept in control and the post-event drinks ... well I'd had no sleep the previous night so I left early. I believe fun was had by all however.&lt;/p&gt;
&lt;p&gt;My talk? I think it went okay - I was a bit nervous presenting on a subject that doesn't get talked about openly all that much, and worried the audience might throw a few massive spanners in the works (although I am open to change, I don't want to be told outright I'm wrong in the middle of a talk!)&lt;/p&gt;
&lt;p&gt;I spoke a bit fast, and had a minor emergency at the start when realising I needed an adapter for my laptop, but was saved by the team whose job it was to babysit me and massive thanks goes to them for saving my presentation :)&lt;/p&gt;
&lt;p&gt;My slides can be found &lt;a href="http://fear.the.codeofrob.com/ddd8slides.zip"&gt;here&lt;/a&gt;, and demo code can be found &lt;a href="http://fear.the.codeofrob.com/ddd8code.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The nerd dinner multi-tenant example can be found on the MvcEx codeplex site (&lt;a href="http://mvcex.codeplex.com"&gt;http://mvcex.codeplex.com&lt;/a&gt;) - but I'll be hoping to improve it beyond its "suitable for demo" stage and do some blog entries on the rationale behind some of the decisions/concepts found within over the coming weeks.&lt;/p&gt;
&lt;p&gt; It's not perfect, it's not anywhere near done and as I keep telling people, it's just for reference purposes (at present), feel free to make suggestions, contributions and etc and we'll get there in the end. Multi-tenancy is the future you know?&lt;/p&gt;&lt;img src="http://blog.codeofrob.com/aggbug/8.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2010/01/31/ddd8-post-event.aspx</guid>
            <pubDate>Sun, 31 Jan 2010 18:01:55 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/8.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2010/01/31/ddd8-post-event.aspx#feedback</comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/8.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/8.aspx</trackback:ping>
        </item>
        <item>
            <title>Dynamically Switching between Master Pages in ASP.NET MVC</title>
            <link>http://blog.codeofrob.com/archive/2009/11/01/dynamically-switching-between-master-pages-in-asp.net-mvc.aspx</link>
            <description>&lt;p&gt;&lt;font face="Arial"&gt;When developing a web application that's designed for re-deployment in a number of different environments (such as a blogging engine/forum system/etc), it's helpful to be able to re-skin and re-structure  the application without modifying any application files.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;To a very large extent, this can be achieved through the use of an alternative set of cascading style sheets and this works for a large number of people. However if you take a look on programming websites such as Stack Overflow the question of how to change the master page at runtime is still an oft-asked one.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In ASP.NET Forms the solution was to simply subclass Page, override PreInit and change the MasterPage property based on some application variable. The master page specified by the corresponding ASPX file could even be read out and used to determine which themed master page to use. (A useful function if you had multiple master pages used throughout the site).&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class ThemedPage : Page
    {
        protected override void OnPreInit(EventArgs e)
        {
            if (this.MasterPageFile.EndsWith("MasterOne.Master", StringComparison.InvariantCultureIgnoreCase))
            {
                // TODO: Some logic here to find the right master page based on theme!
                this.MasterPageFile = "/Views/Shared/MasterThree.Master";
            }

            base.OnPreInit(e);
        }
    }&lt;/pre&gt;
&lt;p&gt;&lt;font face="Arial"&gt;In ASP.NET MVC the playing field has been altered somewhat, and there are a number of options to consider when creating an application with dynamic master pages.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The most championed solutions found on the afore-mentioned programming websites are to either pass the master page name into the View() method when returning a ViewResult , or to create a custom view engine which specifies the master page.&lt;/font&gt;&lt;/p&gt;
&lt;h5&gt;Passing the master page name into the View method&lt;/h5&gt;
&lt;font face="Arial"&gt;
&lt;p&gt;&lt;font face="Arial"&gt;When returning a ViewResult via any of the built in methods (Controller.View()) the option is provided to pass in the name of as master page - and the default view engine will look for a master page with that name in the ~/Views/Shared directory.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Alternatively you can modify the ViewResult  before returning it from your action method - which is probably the preferred option in most cases  as you probably don't want to be passing in the name of the view all the time too.&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        public ActionResult SomePage()
        {
            return View("SomePage", "MasterTwo");
        }&lt;/pre&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        public ActionResult SomeOtherPage()
        {
            var view = View();
            view.MasterName = "MasterTwo";
            return view;
        }&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It is obvious however from these two examples that this is  an un-maintainable solution; having to specify the master page on every single action is going to get tedious and if you decide to change this solution for a different one later on you're going to have to go back and modify all of those method calls.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This leads us nicely on to the next possible solution, of having this work done for us globally by the controller.&lt;/font&gt;&lt;/p&gt;
&lt;/font&gt;&lt;font face="Arial"&gt;It would be possible to pass in the name of a different master page by using a helper somewhere that knew the details of the current theme and therefore the names of the master pages it uses.&lt;/font&gt;&lt;/font&gt;
&lt;h5&gt;Overriding OnActionExecuted on the Controller class&lt;/h5&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;Rather than specify the master page name as the result of every single Action method, you could either create a base controller or override OnActionExecuted on a case-by-case basis.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;OnActionExecuted gives you a chance to modify the result after an action has been invoked, which means you can take the ViewResult which was returned by an action and set the MasterName on it in this location.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;You could even detect whether the MasterName property had been set, and not override it if an action has already explicitly set it.&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            var action = filterContext.Result as ViewResult;
            if (action != null &amp;amp;&amp;amp; String.IsNullOrEmpty(action.MasterName))
            {
                action.MasterName = "MasterThree";
            }
            base.OnActionExecuted(filterContext);
        }&lt;/pre&gt;
&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This gives you the power of being able to specify a master page per controller and still have the flexibility of overriding it per action. &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; It's still not ideal though, there is a certain amount of manual work required in doing this that you wouldn't want if you were going to be developing a large system with a substantial number of controllers or actions.&lt;br /&gt;
&lt;/font&gt;&lt;/p&gt;
&lt;h5&gt;Custom View Engine&lt;/h5&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Moving further up the processing chain, the Custom ViewEngine allows the application to specify the master file for any request.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;For the purposes of this example I'll derive my custom view engine from the standard built-in WebFormViewEngine as it requires the least work to get up and running.&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class ThemedViewEngine : WebFormViewEngine
    {
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            if (string.IsNullOrEmpty(masterName))
            {
                masterName = "MasterOne";
            }
            return base.FindView(controllerContext, viewName, masterName, useCache);
        }
    }&lt;/pre&gt;
&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is registered in place of the built in view engine like so:&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new ThemedViewEngine());&lt;/pre&gt;
&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Now let's take a look at that code - passed in to the method we're overriding (FindView) is a string called masterName.  This is where that string ends up if you use either of the two previous two methods to specify the master page.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;It follows on therefore that just like the last example you can do a check here to see if a master page has already been specified by the previous two methods, and specify one if one has not been set already.&lt;/font&gt;&lt;/p&gt;
&lt;h5&gt;ViewPage - OnPreInit&lt;/h5&gt;
&lt;p&gt;&lt;font face="Arial"&gt;All of the above methods completely ignore the master page directive set in the view itself - which is in my opinion a little bit bonkers.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;By specifying a master page in the ASPX view, you allow the compiler to verify that the right ContentPlaceHolders are overridden  and therefore if you enable compilation of your views you get a check that your view are valid.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Consider for  example the site that has a number of base master pages, one of my personal sites for example has three master pages which are used in different circumstances and each of them have different ContentPlaceHolders because they're for use in completely different functional situations.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The application is probably unaware of these directives (and indeed should be probably be de-coupled from such concerns as whether a page is using a particular master page or not) and therefore shouldn't be making the decision as to which master page to use!&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;ASP.NET MVC is built on top of ASP.NET Forms however, so it turns out that we can ignore the delightfully helpful methods given to us in ASP.NET MVC and skip right back to our original solution of overriding OnPreInit on the base Page class.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Knowing that ViewPage is inherited from the ASP.NET Forms Page, so we can create ThemableViewPage&lt;/font&gt;&lt;/p&gt;
&lt;font face="Arial"&gt;
&lt;pre class="brush: csharp;" title="code"&gt;    public class ThemedViewPage&amp;lt;T&amp;gt; : ViewPage&amp;lt;T&amp;gt; where T : class
    {
        protected override void OnPreInit(EventArgs e)
        {
            if (this.MasterPageFile.EndsWith("MasterOne.Master", StringComparison.InvariantCultureIgnoreCase))
            {
                // TODO: Some logic here to find the right master page based on theme!
                this.MasterPageFile = "/Views/Shared/MasterThree.Master";
            }

            base.OnPreInit(e);
        }
    }

    public class ThemedViewPage : ThemedViewPage&amp;lt;Object&amp;gt; { }&lt;/pre&gt;
&lt;/font&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Note: I create a generic version and a non generic version so we can use it on non strong-typed pages (Some people use these, I don't know why!)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;We can use the same theme code we used in the original example to solve the problem - and best of all, it is still compatible with the previous three methods - so if a different master page is specified by either an Action, a Controller or the ViewEngine this logic will still work.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The only caveats that I can see are that this method is quite dependent on the default WebFormView implementation, and that every view needs to be set up to inherit from this custom ViewPage .&lt;/font&gt;&lt;/p&gt;
&lt;h5&gt;Summary&lt;/h5&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;Switching between master pages is still a bit of a fuzzy topic, and the options given to us in ASP.NET MVC are a bit inadequate. There is still the question as to whether we should be attempting to do this at all given how powerful CSS is - but if you really need to, this blog entry should give you a helpful pointer in the right direction.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;In the projects I own technically where this sort of functionality is going to be requested, I'll be sticking to the OnPreInit method until something better comes up.&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;font face="Arial"&gt;&lt;hr /&gt;
Technorati tags: &lt;a rel="tag" href="http://technorati.com/tags/ASP.NET"&gt;ASP.NET&lt;/a&gt;, &lt;a rel="tag" href="http://technorati.com/tags/ASP.NET+MVC"&gt;ASP.NET MVC&lt;/a&gt;, &lt;a rel="tag" href="http://technorati.com/tags/Master+Pages"&gt;Master Pages&lt;/a&gt;, &lt;a rel="tag" href="http://technorati.com/tags/Themes"&gt;Themes&lt;/a&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;/font&gt;&lt;img src="http://blog.codeofrob.com/aggbug/4.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Rob Ashton</dc:creator>
            <guid>http://blog.codeofrob.com/archive/2009/11/01/dynamically-switching-between-master-pages-in-asp.net-mvc.aspx</guid>
            <pubDate>Sun, 01 Nov 2009 18:44:54 GMT</pubDate>
            <wfw:comment>http://blog.codeofrob.com/comments/4.aspx</wfw:comment>
            <comments>http://blog.codeofrob.com/archive/2009/11/01/dynamically-switching-between-master-pages-in-asp.net-mvc.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://blog.codeofrob.com/comments/commentRss/4.aspx</wfw:commentRss>
            <trackback:ping>http://blog.codeofrob.com/services/trackbacks/4.aspx</trackback:ping>
        </item>
    </channel>
</rss>