X

Subscribe To Our Mailing List

P.S I will never spam you...100% GUARANTEED!

Sunday, November 30, 2014

Overriding razor view engine

Introduction of overriding razor view engine

View Engines are used to render the HTML from your views to the browser. These View Engines can be customized in our own way. So this article focuses on customizing the default view engine.
There are basically 2 view engines 

  • Razor View EngineThis is an popular view engine and it was introduced with MVC3. Namespace for Razor Engine is System.Web.Razor .Razor uses @ symbol as shown in the below code snippet -
  • @foreach(var item in Model) {
        <tr>
            <td>@item.ID</td>
        </tr>
    }
  • Web Form (ASPX) View EngineThis is the default view engine for the Asp.net MVC and was  included with Asp.net MVC from the beginning. Namespace for WebFormEngine is System.Web.Mvc.WebFormViewEngine. Below is the code snippet with WebformEngine syntax -
  • <% foreach(var item in Model) { %>
        <tr>
            <td> <%: item.ID %> </td>
        </tr>
    <% } %>

How Razor View Engine Works 
Default View Engine searches the page in the corresponding Controller folder and in Shared folder under Views folder.
For an instance consider you have "Index" action (say it loads Index.cshtml) in the "Home" controller and by routing you have configured that to be loaded first when you run the application. 
In the above scenario "Index.cshtml" searched in "Home" folder and "Shared" folder under Views. 

Customizing Razor View Engine
So for the demonstration purpose lets add new folder called "AllViews" under Views folder. Now lets add "Index.html" inside this newly created folder. Below image shows my solution explorer view -

overriding razor view engine












As you can see i removed the "Index.cshtml" view from "Home" folder. So whenever Index action of the home controller is called it should search the "Index.cshtml" in "AllViews" folder.

Below is the code to customize the path of view -


public class CustomViewEngine : RazorViewEngine
{

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, 
                              string masterName, bool useCache) 
        {
           string viewPath = string.Empty;
           string masterPath = string.Empty; 
           string fullPath = string.Empty;
           string controllerName = controllerContext.RouteData.Values["controller"].ToString();
           string actionName = controllerContext.RouteData.Values["action"].ToString();

           if (HttpContext.Current.Session != null && HttpContext.Current.Session["TestFolder"] != null)
           {
               string testFolder = HttpContext.Current.Session["TestFolder"].ToString();

               if (!string.IsNullOrWhiteSpace(testFolder))
               {
                    // Get the value for your config instead of hardcoding
                   viewPath = "~/Views/" + testFolder + "/" + viewName + ".cshtml"; 
                  //masterPath = "~/Shared/" + masterName;  // Use it if required

                   fullPath = HttpContext.Current.Server.MapPath(viewPath);

                  if (System.IO.File.Exists(fullPath))
                  {
                       return new ViewEngineResult(base.CreateView(controllerContext, viewPath, 
                                                     masterPath), this);
                  }

               }
           }
           
           //Search in default Location "ControllerName/ViewName -- overriding razor view engine
           viewPath = "~/Views/" + controllerName + "/" + viewName + ".cshtml";
           return new ViewEngineResult(base.CreateView(controllerContext, viewPath, masterPath), this);
       }
 }

So as per the code priority is given to "AllViews" folder if view not found in that path then it searches in the default locations as discussed above. And as you can see "Session["TestFolder]" which has value "AllViews". 
Now we have to configure this custom view engine in Global.asax file


protected void Application_Start()
  {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            // Configuration Starts Here
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new CustomViewEngine());
  }

Similarly for Partial View we use the below method-

 
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, 
                                                       string partialViewName, bool useCache)
  {
         //Do Something Here
  }