Sankarsan Bose

.NET Diaries

  Home  |   Contact  |   Syndication    |   Login
  7 Posts | 0 Stories | 5 Comments | 0 Trackbacks

News

Twitter












Archives

Post Categories

Thursday, December 25, 2008 #

In an ASP.NET MVC application the request URI is of the following format {controller}/{action}/{id}.Based on the controller name in the URI the ControllerFactory instantiates the appropriate Controller class and then based on the action in the URI the corresponding action method in the Controller is executed.Action method then dispatches the right view and by default the location of the views are in the path ~/Views/<Controller>/<Action>.aspx.But how can we change this default behavior and make the location of the view configurable based on Web.config settings.

This can be done very easily by overriding the FindView method of System.Web.Mvc.VirtualPathProviderViewEngine.In my previous post I have discussed in details about the Classes and Interfaces related to View Engines and how views are located.So we have create a class inheriting System.Web.Mvc.WebFormViewEngine and then override the FindView method as shown below:

public  class CustomViewEngine:WebFormViewEngine
{
     public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
     {
         string viewPath = string.Empty;
         string masterPath = string.Empty;
         ViewEngineResult result = null;

         if (controllerContext == null) throw new ArgumentNullException("ControllerContext cannot be null");
         if (viewName == null || viewName.Length == 0) throw new ArgumentNullException("ViewName cannot be null");

        //Read View Path from Web.config

         viewPath = ConfigurationManager.AppSettings[viewName];
         if (viewPath == null || viewPath.Length == 0) throw new ConfigurationErrorsException("View Path cannot be null or empty.Please check web.config");
         masterPath = ConfigurationManager.AppSettings[masterName];

       //Create an instance of IView and wrap the results in an ViewEngineResult instance

         result = new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
         return result;

     }
}

Now we need to remove the default view engine and plug in our custom view engine in Application_Start event of Global.asax.cs as follows:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new SB.Web.Mvc.CustomViewEngine());

Lastly we need to add the actual view paths in web.config as shown below:

<add key="Index" value="~/Pages/Index.aspx"/>
<add key="About" value="~/Pages/About.aspx"/>

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

In this post I will be discussing about the process of locating views in ASP.NET MVC and design of the classes & interfaces involved.In the controller class we normally write a method for each action to be performed and code in that method looks something like this:

public ActionResult About()
       {
           ViewData["Title"] = "About Page";

           return View();
       }

Note the method View() which is invoked at the last step.The method View() of System.Web.Mvc.Controller class returns System.Web.Mvc.ViewResult.Now let us quickly examine the class hierarchy of ViewResult class.

ViewResult Class Hierarchy

  1. System.Web.Mvc.ActionResult - This abstract class has the following abstract method
    • public abstract void ExecuteResult(System.Web.Mvc.ControllerContext context)
  2. System.Web.Mvc.ViewResultBase - This abstract class inherits from System.Web.Mvc.ActionResult.
    • It exposes an abstract method protected abstract System.Web.Mvc.ViewEngineResult FindView(System.Web.Mvc.ControllerContext context).
    • Provides an implementation of public override void ExecuteResult(System.Web.Mvc.ControllerContext context).The major steps in this method are
      • Calls FindView and executes the implementation provided by the subclasses.This method returns an instance of System.Web.Mvc.ViewEngineResult.
      • Calls System.Web.Mvc.ViewEngine.Result.View.Render method to render the View.
    • It also exposes a public property public System.Web.Mvc.IViewEngine ViewEngine { set; get; }
  3. System.Web.Mvc.ViewResult - This abstract class inherits from System.Web.Mvc.ViewResultBase and provides an implementation of FindView method.From FindView it invokes the method ViewEngine.FindView(ControllerContext, string, string)

Thus the control is transferred to the ViewEngine and ViewEngine plays the main role in locating the views.For simplicity of discussion I will discuss about Webforms based views only keeping partial views out of context.

View Engine Class Hierarchy

  1. System.Web.Mvc.IViewEngine- This interface defines the following method
    • System.Web.Mvc.ViewEngineResult FindView(System.Web.Mvc.ControllerContext controllerContext, string viewName, string masterName)
      • Locates the view based on View name,MasterPage name and controller name from the ControllerContext.
    • void ReleaseView(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.IView view)
      • Disposes the View instances if IDisposable is implemented
    • System.Web.Mvc.ViewEngineResult FindPartialView(System.Web.Mvc.ControllerContext controllerContext, string partialViewName)
  2. System.Web.Mvc.VirtualPathProviderViewEngine - This abstract class implements the IViewEngine interface and exposes two abstract methods
    • protected abstract System.Web.Mvc.IView CreatePartialView(System.Web.Mvc.ControllerContext controllerContext, string partialPath)
    • protected abstract System.Web.Mvc.IView CreateView(System.Web.Mvc.ControllerContext controllerContext, string viewPath, string masterPath)
      • This method is implemented by subclasses and creates an instance of type System.Web.Mvc.IView.
    • It also exposes three public properties
      • public string[] MasterLocationFormats { set; get; }
        • Specifies the format of the path where to look for master pages.The default values are ~/Views/{1}/{0}.master,~/Views/Shared/{0}.master where {0} is replaced by controller name and {1} by action name
      • public string[] ViewLocationFormats { set; get; }
        • Specifies the format of the path where to look for forms and user controls.The default values are ~/Views/{1}/{0}.aspx,~/Views/{1}/{0}.ascx,~/Views/Shared/{0}.aspx,~/Views/Shared/{0}.ascx where {0} is replaced by controller name and {1} by action name
      • public string[] PartialViewLocationFormats { set; get; }
  3. System.Web.Mvc.WebFormViewEngine - This class inherits from VirtualPathProviderViewEngine and provides implementation for CreateView and CreatePartialView.CreateView returns an instance of System.Web.Mvc.WebFormView.

View Class Hierarchy

  1. System.Web.Mvc.IView- This interface defines the following method
    • void Render(System.Web.Mvc.ViewContext viewContext, System.IO.TextWriter writer)
      • Renders the view content
  2. System.Web.Mvc.WebFormView- This class implements the IView interface and renders the aspx and ascx pages.

I was actually looking for a way to customize the way ASP.NET MVC locates the views and came to know about all these.I really liked this extensible design particularly the judicious use of Template Design Pattern.In my next post I will discuss about how to customize the locating of the views.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati