ASP.NET MVC works with the concept of Convention over Configuration. that means, the programmer do not need to explicitly do many things and MVC will take care of those if he follows the conventions. One good example is, To return a view, you simply write one line Return View() and it will return the view from the appropriate directory ( assuming the programmer followed the convention and kept the view file in ~/Views/ThatControllerName/ folder with same name as of the action method. but MVC is extensible. If you want to override the convention. you can always do that. This post shows how rendering views from custom folders in asp.net mvc is possible.

By default, you will have a Views folder in root and you can have multiple folders under that with same name as of your controller name. Each of those folder will have views (.cshtml files) for your action methods. so the default structure will look like this for a controller called CustomerController with 3 action methods. index, edit and details.

View directory structure

 

Returning view from a different location

If you want to return a view from a different location, you can do it by specifying the full path to the view file when calling the View method. for example, if you want to return a view (index.cshtml) from a folder called Customer under UI folder which is in the root of the application,  you can do it like this

public ActionResult Index()
{
    return View("~/UI/Customer/Index.cshtml");
}

 

Assuming you have the _viewStart.html and web.config present in your UI folder.

The above method works. but it is not a good solution to hardcode the location like this. What if we have a lots of controllers and action methods ? , are we going to hard code it like this ? No !!!

What we can do is we can extend the razor view engine and tell it to look for views in our custom location.  so if you look at the sourcecode of RazorViewEngine, you can see that the default  location (what the convention follows) is there.

So let's extend the RazorViewEngine and create our own view engine. Remember that we are going to simply change the View's default location only. rest of the view functionality is going to be same (as of Razor). So we will create a class which extends from RazorViewEngine class and write code like this.

public class MyCustomViewEngine : RazorViewEngine
{
    public MyCustomViewEngine()
    {
        string[] viewLocationFormatArr=new string[4];
        viewLocationFormatArr[0] = "~/UI/{1}/{0}.cshtml";
        viewLocationFormatArr[1] = "~/UI/{1}/{0}.vbhtml";
        viewLocationFormatArr[2] = "~/UI/Shared/{1}/{0}.vbhtml";
        viewLocationFormatArr[3] = "~/UI/Shared/{1}/{0}.vbhtml";
        this.ViewLocationFormats = viewLocationFormatArr;

        string[] masterLocationFormatArr = new string[4];
        masterLocationFormatArr[0] = "~/UI/{1}/{0}.cshtml";
        masterLocationFormatArr[1] = "~/UI/{1}/{0}.vbhtml";
        masterLocationFormatArr[2] = "~/UI/Shared/{1}/{0}.vbhtml";
        masterLocationFormatArr[3] = "~/UI/Shared/{1}/{0}.vbhtml";
        this.MasterLocationFormats = masterLocationFormatArr;

        string[] partialViewLocationFormatArr = new string[4];
        partialViewLocationFormatArr[0] = "~/UI/{1}/{0}.cshtml";
        partialViewLocationFormatArr[1] = "~/UI/{1}/{0}.vbhtml";
        partialViewLocationFormatArr[2] = "~/UI/Shared/{1}/{0}.vbhtml";
        partialViewLocationFormatArr[3] = "~/UI/Shared/{1}/{0}.vbhtml";
        this.ViewLocationFormats = partialViewLocationFormatArr;

    }
}

Here i updated only the View related things. I did not update the other 3 properties which handles the location for Areas. But it is going to be the same way. You can simply mention the new folder name and it will be fine.

RazorViewEngine class resides in System.Web.Mvc namespace which is in System.Web.Mvc dll

Now what we need to do is to register our new ViewEngine. So let's go to the global.asax's Application_Start event, clear existing view engines and register our new one.

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    var ourViewEngine = new MyCustomViewEngine();
    ViewEngines.Engines.Add(ourViewEngine);

    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

That is all you need to make it happen. Hit F5 and you can see your app is now bringing views from the UI folder, instead of the Views folder.

 

You need to update the _viewStart.cshtml file to update the layout files location as well.

@{
    Layout = "~/UI/Shared/_Layout.cshtml";
}