1
votes

Is it possible to define more folders for ASP.NET MVC to search for Views or Partials?

For example, if I browse to /Home/Index and the Index action returns View(), ASP.NET MVC will look at the following locations:

  • ~/Views/Home/Index.aspx
  • ~/Views/Home/Index.ascx
  • ~/Views/Shared/Index.aspx
  • ~/Views/Shared/Index.ascx
  • ~/Views/Home/Index.cshtml
  • ~/Views/Home/Index.vbhtml
  • ~/Views/Shared/Index.cshtml
  • ~/Views/Shared/Index.vbhtml

I want to create another folder, say ~/Views/PartivalViews/, that will be searched.

Obviously I'm looking for this as a tidy way to store my PartialViews.

2

2 Answers

5
votes

You could write a custom view engine where you could specify additional folders where ASP.NET MVC will look for views.

The idea here is to write a class deriving from RazorViewEngine and in its constructor set the various properties such as:

  • AreaViewLocationFormats
  • AreaMasterLocationFormats
  • AreaPartialViewLocationFormats
  • ViewLocationFormats
  • MasterLocationFormats
  • PartialViewLocationFormats

Here are the default values that you could feel free to override:

public RazorViewEngine(IViewPageActivator viewPageActivator) : base(viewPageActivator)
{
    base.AreaViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.vbhtml" };
    base.AreaMasterLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.vbhtml" };
    base.AreaPartialViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.vbhtml" };
    base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" };
    base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" };
    base.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" };
    base.FileExtensions = new string[] { "cshtml", "vbhtml" };
}

And then simply register your custom view engine in Application_Start:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MyRazorViewEngine());

In this example I have removed all other default view engines (WebForms and Razor) before registering our custom one.

0
votes

If you wonder how to proceed from Darin answer above, this is how I implemented it. All credit goes to Darin and Owen.

I basically wanted to place all my Partial Views under Views/Controller/Shared folder. So I only replaced the "PartialViewLocationFormats" property of the "RazorViewEngine". Added "~/Views/{1}/Shared/{0}.cshtml" as the first element in the list, so that ViewEngine will look at the "Views/Controller/Shared" folder first.

Then as Darin explained above in the global.asax, clear the existing view engines and add the new one.

ViewEngines.Engines.Add(new CustomRazorViewEngine());

Hope this helps someone.

public class CustomRazorViewEngine : RazorViewEngine
    {
        public CustomRazorViewEngine()
        {
            var newLocationFormat = new[]
                                    {
                                        "~/Views/{1}/Shared/{0}.cshtml",
                                        "~/Views/{1}/{0}.cshtml", 
                                        "~/Views/{1}/{0}.vbhtml", 
                                        "~/Views/Shared/{0}.cshtml", 
                                        "~/Views/Shared/{0}.vbhtml"
                                    };

            PartialViewLocationFormats = newLocationFormat;
        }

    }