January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Customize View, Partial View and Layout Search Locations in ASP.NET MVC

By default ASP.NET MVC stores all the views associated to a controller inside a sub-folder of Views folder. On the same lines partial views and layout pages are stored inside Shared sub-folder under Views folder. Although this default arrangement works well in most of the cases, at times you may want to deviate from this convention based arrangement and store views, partial views and layouts in some different folder structure. Consider, for example, a huge application that wants to arrange partial views in several sub-folders inside Shared folder. Or some application may want to store views outside views folder. In such cases when you use view names in methods such as View(), Html.Partial() and PartialView() the system won't be able to find the required .cshtml files. Of course, you can use fully qualified paths in some cases but that makes your code rigid because any future change in the paths will require changes at multiple places.

Luckily, you can easily deal with the situation by creating a custom view engine. This article tells you how.

Let's assume that you wish to store partial views and layouts in the following custom folder structure:

Notice that partial views and layouts aren't stored directly inside Shared folder. They are stored inside PartialViews and Layouts sub-folders of Shared folder. Views are stored as per default convention. Let's assume that Index view uses Test.cshtml like this:

@Html.Partial("Test")

If you run the application under these settings, you will get this error in the browser:

As you can see, the system is unable to find Test.cshtml residing inside PartialViews sub-folder.

To deal with this situation you can create a custom view engine and then supply the custom search locations to the new view engine. Don't worry. Creating a custom view engine to accomplish this task is quite straightforward. Let's do that now.

Add a new class to your project and give it whatever name you wish to give to the new view engine. In my code I am calling my view engine as BinaryIntellectViewEngine. The complete class is shown below:

public class BinaryIntellectViewEngine : RazorViewEngine
{
    public BinaryIntellectViewEngine()
    {
        string[] locations = new string[] {  
            "~/Views/{1}/{0}.cshtml",  
            "~/Views/Shared/PartialViews/{0}.cshtml",  
            "~/Views/Shared/Layouts/{0}.cshtml"
        };

        this.ViewLocationFormats = locations;
        this.PartialViewLocationFormats = locations;
        this.MasterLocationFormats = locations;
    }
}

The BinaryIntellectViewEngine class inherits from RazorViewEngine base class. In our example we are using Razor view engine and hence the above code inherits from RazorViewEngine class. This inbuilt class comes from System.Web.Mvc namespace.

The magic that makes the custom locations work happens inside the constructor of the custom view engine class. Here, we create an array of strings. This array contains a list of all locations where the view engine should look for the views, partial views and layout pages. Notice the convention used in the paths. The placeholder {0} contains the view or payout page name whereas {1} contains the folder name (controller name).

The three base class properties namely ViewLocationFormats, PartialViewLocationFormats and MasterLocationFormats point to the list of search locations for views, partial views and layout pages respectively. In our example, all the three properties are set to the location string array.

This completes our custom view engine. The final step is to register this new view engine with the MVC framework. This is done inside Application_Start event in Global.asax.

void Application_Start(object sender, EventArgs e)
{
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    RouteConfig.RegisterRoutes(RouteTable.Routes);

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new BinaryIntellectViewEngine());
}

The Application_Start event handler clears the existing registered view engines by calling Clear() method of ViewEngines.Engines collection. Then the new view engine is added using Add() method.

That's it! If you run the application now you should see the Test partial view rendered successfully.

 


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Meditation and Mindfulness to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 03 November 2014


Tags : ASP.NET MVC C#