The View Engine

Scott Hanselman, community program manager at Microsoft, likes to call the view engine “just an angle bracket generator.” In simplest terms, that's exactly what it is. A view engine will take an in-memory representation of a view and turn it into whatever other format you like. Usually, this means that you will create a CSHTML file containing markup and script, and ASP.NET MVC's default view engine implementation, the RazorViewEngine, will use some existing ASP.NET APIs to render your page as HTML.

View engines aren't limited to using CSHTML pages, nor are they limited to rendering HTML. You'll see later how you can create alternate view engines that render output that isn't HTML, as well as unusual view engines that take a custom DSL (Domain Specific Language) as input.

To better understand what a view engine is, let's review the ASP.NET MVC life cycle (very simplified in Figure 3.6).

A lot more subsystems are involved than Figure 3.6 shows; this figure just highlights where the view engine comes into play—which is right after the Controller action is executed and returns a ViewResult in response to a request.

It is very important to note here that the Controller itself does not render the view; it simply prepares the data (that is, the model) and decides which view to display by returning a ViewResult instance. As you saw earlier in this chapter, the Controller base class contains a simple convenience method, named View, used to return a ViewResult. Under the hood, the ViewResult calls into the current view engine to render the view.

Configuring a View Engine

As just mentioned, it's possible to have alternative view engines registered for an application. View engines are configured in Global.asax.cs. By default, there is no need to register other view engines if you stick with just using RazorViewEngine (and the WebFormViewEngine is also registered by default).

However, if you want to replace these view engines with another, you could use the following code in your Application_Start method:

protected void Application_Start() {
  ViewEngines.Engines.Clear();
  ViewEngines.Engines.Add(new MyViewEngine());
  RegisterRoutes(RouteTable.Routes);
} 

Code snippet 3-14.txt

Engines is a static ViewEngineCollection used to contain all registered view engines. This is the entry point for registering view engines. You needed to call the Clear method first because RazorViewEngine and WebFormViewEngine are included in that collection by default. Calling the Clear method is not necessary if you want to add your custom view engine as another option in addition to the default one, rather than replace the default view engines.

In most cases though, it's probably unnecessary to manually register a view engine if it's available on NuGet. For example, to use the Spark view engine, after creating a default ASP.NET MVC 3 project, simply run the NuGet command, Install-Package Spark.Web.Mvc. This adds and configures the Spark view engine in your project. You can quickly see it at work by renaming Index.cshtml to Index.spark. Change the mark up to the following to display the message defined in the controller.

<!DOCTYPE html>
<html>
<head>
    <title>Spark Demo</title>
</head>
<body>
    <h1 if="!String.IsNullOrEmpty(ViewBag.Message)">${ViewBag.Message}</h1>
    <p>
        This is a spark view.
    </p>
</body>
</html> 

Code snippet 3-15.txt

Code snippet 3-15 shows a very simple example of a Spark view. Notice the special if attribute which contains a boolean expression that determines whether the element it's applied to is displayed or not. This declarative approach to controlling markup output is a hallmark of Spark.

Finding a View

The IViewEngine interface is the key interface to implement when building a custom view engine:

UnFigure
public interface IViewEngine {
    ViewEngineResult FindPartialView(ControllerContext controllerContext, 
        string partialViewName, bool useCache);
    ViewEngineResult FindView(ControllerContext controllerContext, string viewName,
        string masterName, bool useCache);
    void ReleaseView(ControllerContext controllerContext, IView view);
}

Code snippet 3-16.txt

With the ViewEngineCollection, the implementation of FindView iterates through the registered view engines and calls FindView on each one, passing in the specified view name. This is the means by which the ViewEngineCollection can ask each view engine if it can render a particular view.

The FindView method returns an instance of ViewEngineResult, which encapsulates the answer to the question, “Can this view engine render the view?” (See Table 3.2.)

Table 3.2: ViewaEngineResult Properties

Property Description
View Returns the found IView instance for the specified view name. If the view could not be located, it returns null.
ViewEngine Returns an IViewEngine instance if a view was found; otherwise null.
SearchedLocations Returns an IEnumerable<string> that contains all the locations that the view engine searched.

If the IView returned is null, the view engine was not able to locate a vfiew corresponding to the view name. Whenever a view engine cannot locate a view, it will return the list of locations it checked. These are typically file paths for view engines that use a template file, but they could be something else entirely, such as database locations for view engines that store Views in a database.

Note that the FindPartialView method works in the same way as FindView, except that it focuses on finding a partial view. It is quite common for view engines to treat Views and partial Views differently. For example, some view engines automatically attach a master view (or layout) to the current view by convention. It's important for that view engine to know whether it's being asked for a full view or a partial view. Otherwise, every partial view might have the master layout surrounding it.

The View Itself

The IView interface is the second interface one needs to implement when implementing a custom view engine. Fortunately, it is quite simple, containing a single method:

UnFigure
public interface IView {
    void Render(ViewContext viewContext, TextWriter writer);
}

Code snippet 3-17.txt

Custom Views are supplied with a ViewContext instance, which provides the information that might be needed by a custom view engine, along with a TextWriter instance. The view is expected to consume the data in the ViewContext (such as the view data and model) and then call methods of the TextWriter instance to render the output.

The ViewContext contains the following properties, accessible by the view as shown in Table 3.3.

Table 3.3: ViewContext Properties

Property Description
HttpContext An instance of HttpContextBase, which provides access to the ASP.NET intrinsic objects such as Server, Session, Request, Response
Controller An instance of ControllerBase, which provides access to the Controller making the call to the view engine
RouteData An instance of RouteData, which provides access to the route values for the current request
ViewData An instance of ViewDataDictionary containing the data passed from the Controller to the view
TempData An instance of TempDataDictionary containing data passed to the view by the Controller in a special one-request-only cache
View An instance of IView, which is the view being rendered
ClientValidationEnabled Boolean value indicating whether Client Validation has been enabled for the view
FormContext Contains information about the form, used in client-side validation
FormIdGenerator Allows you to override how forms are named (“form0”-style by default)
IsChildAction Boolean value indicating whether the action is being displayed as a result of a call to Html.Action or Html .RenderAction
ParentActionViewContext When IsChildAction is true, contains the ViewContext of this view's parent view
Writer HtmlTextWriter to use for HTML helpers that don't return strings (that is, BeginForm), so that you remain compatible with non-WebForms view engines
UnobtrusiveJavaScriptEnabled New in ASP.NET MVC 3, this property determines whether or not an unobtrusive approach to client validation and AJAX should be used. When true, rather than emitting script blocks into the markup, HTML 5 data-* attributes are emitted by the helpers, which the unobtrusive scripts use as a means of attaching behavior to the markup.

Not every view needs access to all these properties to render a view, but it's good to know they are there when needed.

Alternative View Engines

When working with ASP.NET MVC for the first time, you're likely to use the view engine that comes with ASP.NET MVC: the RazorViewEngine.

The many advantages to this are that it:

  • Is the default
  • Has clean lightweight syntax
  • Has layouts
  • Has HTML encoded by default
  • Has support for scripting with C#/VB
  • Has IntelliSense support in Visual Studio

There are times, however, when you might want to use a different view engine, for example, when you:

  • Desire to use a different language (like Ruby or Python)
  • Render non-HTML output such as graphics, PDFs, RSS, and the like
  • Have legacy templates using another format

Several different third-party view engines are available at the time of this writing. Table 3.4 lists some of the more well-known view engines, but there are likely many others we've never heard of.

Table 3.4: View Engines Properties

View Engine Description
Spark Spark (http://sparkviewengine.com/) is the brainchild of Louis DeJardin (now a Microsoft employee) and is being actively developed with support for both MonoRail and ASP.NET MVC. It is of note because it blurs the line between markup and code using a very declarative syntax for rendering views.
NHaml NHaml (hosted on GitHub at https://github.com/NHaml/NHaml), created by Andrew Peters and released on his blog in December 2007, is a port of the popular Ruby on Rails Haml View engine. It's a very terse Domain Specific Language (DSL) used to describe the structure of XHTML with a minimum of characters.
Brail Brail (part of the MvcContrib project http://mvccontrib.org) is interesting for its use of the Boo Language. Boo is an object-oriented statically typed language for the CLR with a Python language style to it, such as significant white space.
StringTemplate StringTemplate (hosted at Google code http://code.google.com/p/ string-template-view-engine-mvc) is a lightweight templating engine that is interpreted rather than compiled. It's based on the Java StringTemplate engine.
NVelocity NVelocity (http://www.castleproject.org/others/nvelocity) is an Open Source templating engine and a port of the Apache/Jakarta Velocity project, built for Java-based applications. The NVelocity project did quite well for a few years, until 2004, when check-ins stopped and the project slowed down.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.219.130