ASP.NET MVC is a wonderful thing.  One of the many great features is the ability to customize all of the .NET framework’s code by swapping out one implementation and using another.  One such instance is creating a custom view engine, which you can do as illustrated in this example: http://www.singingeels.com/Articles/Creating_a_Custom_View_Engine_in_ASPNET_MVC.aspx.  The point of my article is not to illustrate how this can be done, but about how to customize it for your needs.  By default, the web forms view engine looks for views in the folder of the controller or the shared folder.  So if you try to trigger an action method “Index” within the controller of type CustomerController, a partial view (.ascx) or the view (.aspx) is sought for in the ~/Shared folder or ~/Customer folder.

Now, I tend to like to use partial views in order to separate and reuse functionality a lot.  So I tend to have a lot of partial views that tend to get reused across pages and I don’t want everything to be in the shared folder (by default, partial views have to be in the shared folder or in the same folder as the controller).  So I added some code to the view engine that allowed me to create subfolders within the shared folder and for the view engine to look for the classes there.  Imagine this folder structure:

Shared
    Customers
    Orders
    Products

So the shared folder breaks up my partial views into the folder above. 

Thinking long-term, rather than hard-coding all these folder references and assigning them to the ViewLocationFormats and PartialViewLocationFormats properties, I wanted something that I wouldn’t have to worry about changing later.  So in true ASP.NET MVC framework form, I created some extra code to create the ability to automatically add references to subfolders too.  In order to do this, it’s required to use the VirtualPathProvider class to extract the URL, as in the following code:

public MyViewEngine() {
var locations = new List<string>
{
    “~/Views/{1}/{0}.aspx”,
    “~/Views/{1}/{0}.ascx”,
    “~/Views/Shared/{0}.aspx”,
    “~/Views/Shared/{0}.ascx”
};

var dir = this.VirtualPathProvider.GetDirectory(“~/Views/Shared”);
var subs = dir.Directories.OfType<VirtualDirectory>();

foreach (var sub in subs)
{
    locations.Add(“~” + sub.VirtualPath.Substring(sub.VirtualPath.IndexOf(“/”, 2)) + “{0}.ascx”);
}

base.ViewLocationFormats = locations.ToArray();
base.PartialViewLocationFormats = base.ViewLocationFormats;
}

This is the constructor for the custom view engine.  It contains some additional code to use the VirtualPathProvider property (a property of our custom view engine) to extract the subdirectories of the shared folder.  You see the four hard-coded references at the beginning, and so we need to create virtual path strings (which start with “~” and work from the beginning of the virtual directory) to add to the custom list.  When working with folders using VirtualPathProvider, the issue becomes the way paths are referenced.  By default, the path may be:

/MyVirtualFolder/Views/Shared/Customers/

When you need:

~/Views/Shared/Customers/

And so some additional work to format the path is needed (the substring strips off the virtual directory folder.  Now we have a component that will allow the MVC framework to look for partial views in all subdirectories in the shared folder.