Alternate View Folders in ASP.NET MVC

Posted by on in Blogs
Stephen Walther recently posted a tip on how to load an ASP.NET MVC View from a folder other than Views\{controller}\ or Shared. He notes that it's possible to hardcode the path to a View in your Controller action.  He also states that you should not do this:
Now, I want to be the first to warn you that you should never, never, never use this tip (Please delete this entry from your news aggregator immediately). There is a good reason for following the conventions inherent in an MVC application. Placing your files in known locations makes it easier for everyone to understand your application.

Now, if the only types of Views that you have an application are views which directly correspond to a single controller or widely shared items like master pages, he's right.  With more complicated architectures, you may need other choices, and the MVC framework has an extensibility point built-in for this. To the extent that Stephen's point was that it's never appropriate to hardcode a path inside a controller, however, I completely agree with that. But there may be legitimate reasons to probe other paths, and it's also interesting to look at why the framework looks in these specific places in the first place.

I have, I think, a fairly good reason for wanting the MVC framework to probe other folders when looking for a View.  I'll explain that at the bottom of the post, but first, here's the technique. I want to thank Jens Hofmann for pointing this out.  His needs are slightly different than mine — he wants the framework to always probe different folders, rather than adding one more folder to the list of folders probed — but his post (in German) pointed me in the right direction to solve the problem. In contrast to Jens's tip, I'm going to subclass the default controller and extend its list of paths, rather than replacing it altogether.

The ASP.NET MVC framework uses a class called a ViewLocator to find view files.  The default ViewLocator is a subclass called WebFormViewLocator. This by itself suggests one reason why you might want to replace the ViewLocator; if you're developing an alternate markup language, your views will probably have different template file extensions than a WebForm view, so an alternate ViewLocator will be needed.

What I did was to subclass WebFormViewLocator and add my custom path to the list of paths probed, like this:

public class EntityViewLocator : WebFormViewLocator
public EntityViewLocator()
ViewLocationFormats = ViewLocationFormats.Union(EntityViewFormats).ToArray();

    private static string[] EntityViewFormats = new[] { "~/Views/Entities/{0}.aspx",
"~/Views/Entities/{0}.ascx" };

The class is public for unit testing convenience. Update: Cleaned up code 1 August 2008.

Now you need to assign the ViewLocator to the Controller.  One way to do this is in the Controller itself.  But I already had a ControllerFactory, so I did it there.

So why do I bother with this?  Why not just use the standard folders?

In one of the applications I'm developing now, the great majority of Controllers and Views are dynamically generated to correspond to a type from an Entity Framework model.  I have a very large number of "controllers," but most of them don't actually exist as types or source files.  Instead, a single, generic controller can "pretend" to be a specific controller for a specific entity type. Most entity types share completely dynamic views, with no special knowledge of specific controller/entity types, but a few have entirely custom views, which are tightly bound to certain controllers.  Structurally, it makes sense to group these "entity views," as well as their field templates, together, rather than dumping them in with master pages, or creating a folder to correspond to a "controller name" which doesn't actually exist, since a single controller is used for most entity types.
Comments are not available for public users. Please login first to view / add comments.