Razor View Engine

The previous two sections looked at how to specify a view from within a controller as well as how to add a view. However they didn't cover the syntax that goes inside of a view. ASP.NET MVC 3 includes two different view engines, the new Razor View Engine and the older Web Forms View Engine. This section covers the Razor View Engine which includes the Razor syntax, layouts, partial views, and so on.

What is Razor?

The Razor View Engine is new to ASP.NET MVC 3 and is the default view engine moving forward. This chapter focuses on Razor and does not cover the Web Forms View Engine.

Razor is the response to one of the most requested suggestions received by the ASP.NET MVC feature team—to provide a clean, lightweight simple view engine that didn't contain the “syntactic cruft” contained in the existing Web Forms View Engine. Many developers felt that all that syntactic noise required to write a view created friction when trying to read that view.

This request was finally answered in version 3 of ASP.NET MVC with the introduction of the new Razor View Engine.

Razor provides a streamlined syntax for expressing views that minimizes the amount of syntax and extra characters. It effectively gets out of your way and puts as little syntax as possible between you and your view markup. Many developers who have written Razor views have commented on feeling the view code just flowing from their fingertips, akin to a mind-meld with their keyboard. This feeling is enhanced with the first-rate IntelliSense support for Razor in Visual Studio 2010.

Product Team Aside

UnFigure

The precursor that led to Razor was first started off as a prototype (by Dmitry Robsman ) that attempted to preserve some of the goodness of the ASP.NET MVC approach, while at the same time allowing for a simpler (one page at a time) development model.

His prototype was named Plan9, named after the 1959 science fiction/horror film Plan 9 from Outer Space, considered to be one of the worst movies ever made.

Plan 9 later became ASP.NET Web Pages (the default runtime framework for Web Matrix), which provides a very simple inline style of web development similar in spirit to PHP or classic ASP, but using Razor syntax. Many members of the ASP.NET team still use the term “Plan 9” internally when referring to this technology.

ASP.NET MVC 3 also adopted the Razor syntax, which provides a nice “graduation” story for developers who start with ASP.NET Web Pages but decide to move to ASP.NET MVC.

Razor accomplishes this by understanding the structure of markup so that it can make the transitions between code and markup as smooth as possible. To understand what is meant by this, some examples will help. The following example demonstrates a simple Razor view that contains a bit of view logic:

@{
  // this is a block of code. For demonstration purposes, we'll 
  // we'll create a "model" inline.
  var items = new string[] {"one", "two", "three"};
}
<html>
<head><title>Sample View</title></head>
<body>
  <h1>Listing @items.Length items.</h1>
  <ul>
  @foreach(var item in items) {
    <li>The item name is @item.</li>
  }
  </ul>
</body>
</html>

The previous code sample uses C# syntax which means the file has the .cshtml file extension. Similarly, Razor views which use the Visual Basic syntax will have the .vbhtml file extension. These file extensions are important, as they signal the code language syntax to the Razor parser.

Code Expressions

The key transition character in Razor is the “at sign” (@). This single character is used to transition from markup to code and sometimes also to transition back. There are two basic types of transitions: code expressions and code blocks. Expressions are evaluated and written to the response.

For example, in the following snippet:

<h1>Listing @stuff.Length items.</h1>

notice that the expression @stuff.length is evaluated as an implicit code expression and the result, 3, is displayed in the output. One thing to notice though is that we didn't need to demarcate the end of the code expression. In contrast, with a Web Forms View, which supports only explicit code expressions, this would look like:

<h1>Listing <%: stuff.Length %> items.</h1>

Razor is smart enough to know that the space character after the expression is not a valid identifier so it transitions smoothly back into markup.

Notice that in the unordered list, the character after the @item code expression is a valid code character. How does Razor know that the dot after the expression isn't meant to start referencing a property or method of the current expression? Well, Razor peeks at the next character and sees an angle bracket, which isn't a valid identifier and transitions back into markup mode. Thus the first list item will render out:

<li>The item name is one.</li>

This ability for Razor to automatically transition back from code to markup is one of its big appeals and is the secret sauce in keeping the syntax compact and clean. But it may make some of you worry that there are potential ambiguities that can occur. For example, what if I had the following Razor snippet?

@{
    string rootNamespace = "MyApp";
}
<span>@rootNamespace.Models</span>

In this particular case, what I hoped to be output was:

<span>MyApp.Models</span>

Instead what happens is we get an error that there is no Models property of string. In this admittedly edge case, Razor couldn't understand our intent and thought that @rootNamespace.Models was our code expression. Fortunately, Razor also supports explicit code expressions by wrapping the expression in parentheses:

<span>@(rootNamespace).Models</span>

This tells Razor that .Models is literal text and not part of the code expression.

While we're on the topic of code expressions, we should also look at the case where you intend to show an email address. For example, my email address is:

<span>[email protected]</span>

At first glance, this seems like it would cause an error because @microsoft.com looks like a valid code expression where we're trying to print out the com property of the microsoft variable. Fortunately, Razor is smart enough to recognize the general pattern of an email address and will leave this expression alone.

note

Razor uses a very simple algorithm to determine whether something looks like an email address or not. It's not meant to be perfect, but handles most cases. Some valid emails may appear not to be emails in which case you can always escape the @ sign with a double @@ sign.

But of course, what if you really did mean for this to be an expression? For example, going back to an earlier example in this section, what if you had the following list items:

In this particular case, that expression seems to match an email address so Razor will print it out verbatim. But it just so happened that we expected the output to be something like:

<li>Item_3</li>

Once again, parentheses to the rescue! Any time there's an ambiguity in Razor, you can use parentheses to be explicit about what you want. You are in control.

<li>Item_@(item.Length)</li>

There's one other ambiguity we haven't yet discussed. Suppose your view needs to display some Twitter handles, which conventionally start with an @ sign:

<p>
  You should follow 
  @haacked, @jongalloway, @bradwilson, @odetocode
</p>

Well, Razor is going to attempt to resolve those implicit code expressions and fail. In the case where you need to escape the @ sign, you can do so by using a double @@ sign. Thus this view becomes:

<p>
  You should follow 
  @@haacked, @@jongalloway, @@bradwilson, @@odetocode
</p>

Html Encoding

Because there are many cases where a view is used to display user input, there's always the potential for cross-site script injection attacks (also known as XSS which is covered in more detail in Chapter 7). The good news is that Razor expressions are HTML encoded.

@{
    string message = "<script>alert(‘haacked!’);</script>";
}
<span>@message</span>

This code will not result in an alert box popping up but will instead display the encoded message:

<span>&lt;script&gt;alert(‘haacked!’);&lt;script&gt;</span>

However, in cases where you intend to show HTML markup, you can return an instance of System.Web.IHtmlString and Razor will not encode it. For example, all the view helpers we'll discuss later in this section return instances of this interface. You can also create an instance of HtmlString or use the Html.Raw convenience method:

@{
    string message = "<strong>This is bold!</strong>";
}
<span>@Html.Raw(message)</span>

This will result in the message being displayed without HTML encoding:

<span><strong>This is bold!</strong></span>

This automatic HTML encoding is great for mitigating XSS vulnerabilities by encoding user input meant to be displayed as HTML, but it is not sufficient for displaying user input within JavaScript. For example:

<script type="text/javascript">
    $(function () {
        var message = ‘Hello @ViewBag.Username;
        $("#message").html(message).show(‘slow’);
    });
</script>

In this code snippet, a JavaScript variable, message, is being set to a string, which includes the value of a user-supplied user name. The user name comes from a Razor expression.

Using the jQuery HTML method, this message is set to be the HTML for a DOM element the ID “message.” Even though the user name is HTML encoded within the message string, there is still a potential XSS vulnerability. For example, if someone supplies the following as their user name, the HTML will be set to a script tag that will get evaluated.

x3cscriptx3e%20alert(x27pwndx27)%20x3c/scriptx3e

When setting variables in JavaScript to values supplied by the user, it's important to use JavaScript string encoding and not just HTML encoding. Use the @Ajax.JavaScriptStringEncode to encode the input. Here's the same code again using this method to better protect against XSS attacks.

<script type="text/javascript">
    $(function () {
        var message = ‘Hello @Ajax.JavaScriptStringEncode(ViewBag.Username)’;
        $("#message").html(message).show(‘slow’);
    });
</script>

Code Blocks

In addition to code expressions, Razor also supports code blocks within a view. Going back to the sample view, you may remember seeing a foreach statement:

  @foreach(var item in stuff) {
    <li>The item name is @item.</li>
  }

This block of code iterates over an array and displays a list item element for each item in the array.

What's interesting about this statement is how the foreach statement automatically transitions to markup with the open <li> tag. Sometimes, when people see this code block, they assume that the transition occurs because of the new line character, but the following valid code snippet shows that's not the case:

  @foreach(var item in stuff) {<li>The item name is @item.</li>}

Because Razor understands the structure of HTML markup, it also transitions automatically back to code when the <li> tag is closed. Thus we didn't need to demarcate the closing curly brace at all.

Contrast this to the Web Forms View Engine equivalent snippet where the transitions between code and markup have to be explicitly denoted:

<% foreach(var item in stuff) { %>
    <li>The item name is <%: item %>.</li>
<% } %>

Blocks of code (sometimes referred to as a code block) require curly braces to delimit the block of code in addition to an @ sign.

One example of this is in a multi-line code block:

@{
  string s = "One line of code.";
  ViewBag.Title "Another line of code";
}

Another example of this is when calling methods that don't return a value (i.e. the return type is void):

@{Html.RenderPartial("SomePartial");}

Note that curly braces are not required for block statements such as foreach loops and if statements.

The handy Razor quick reference in the next section, “Razor Syntax Samples,” shows the various Razor syntaxes as well as comparisons to Web Forms.

Razor Syntax Samples

This section provides samples meant to illustrate the syntax for Razor by comparing a Razor example with the equivalent example using the Web Forms View Engine syntax. Each sample is meant to highlight a specific Razor concept.

Implicit Code Expression

As described before, code expressions are evaluated and written to the response. This is typically how you display a value in a view.

Razor <span>@model.Message</span>
Web Forms <span><%: model.Message %></span>

Code expressions in Razor are always HTML encoded.

Explicit Code Expression

As described before, code expressions are evaluated and written to the response. This is typically how you display a value in a view.

Razor <span>ISBN@(isbn)</span>
Web Forms <span>ISBN<%: isbn %></span>

Unencoded Code Expression

In some cases, you need to explicitly render some value that should not be HTML encoded. You can use the Html.Raw method to ensure that the value is not encoded.

Razor <span>@Html.Raw(model.Message)</span>
Web Forms <span><%: Html.Raw(model.Message) %></span>
 or
<span><%= model.Message %></span>

Code Block

Unlike code expressions which are evaluated and outputted to the response, blocks of code are simply, well, sections of code that are executed. They are useful for declaring variables that you may need to use later.

Razor @{
    int x = 123;
    string y = “because.”;
}
Web Forms <%
    int x = 123;
    string y = “because.”;
%>

Combining Text and Markup

This example shows what intermixing text and markup looks like using Razor as compared to Web Forms.

Razor @foreach (var item in items) {
    <span>Item @item.Name.</span>
}
Web Forms <% foreach (var item in items) { %>
    <span>Item <%: item.Name %>.</span>
<% } %>

Mixing Code and Plain Text

Razor looks for the beginning of a tag to determine when to transition from code to markup. However, sometimes you want to output plain text immediately after a code block. For example, in this sample we display some plain text within a conditional block.

Razor @if (showMessage) {
    <text>This is plain text</text>
}
 or
@if (showMessage) {
    @:This is plain text.
}
Web Forms <% if (showMessage) { %>
    This is plain text.
<% } %>

Note that there are two different ways of doing this with Razor. The first case uses the special <text> tag. The tag itself is not written to the response, only its contents. I personally like this approach because it makes logical sense to me. If I want to transition back to markup, use a tag.

Others prefer the second approach, which is a special syntax for switching from code back to plain text.

Escaping the Code Delimiter

As you saw earlier in this chapter, you can display “@” by encoding it using “@@.” Alternatively, you always have the option to use HTML encoding.

Razor My Twitter Handle is &#64;hacked
or
My Twitter Handle is @@haacked
Web Forms &lt;% expression %&gt; marks a code
nugget.

Server Side Comment

Razor includes a nice syntax for commenting out a block of markup and code.

Razor @*
This is a multiline server side comment.
@if (showMessage) {
    <h1>@ViewBag.Message</h1>
}
All of this is commented out.
*@
Web Forms <%--
This is a multiline server side comment.
<% if (showMessage) { %>
    <h1><%: ViewBag.Message %></h1>
<% } %>
All of this is commented out.
--%>

Calling a Generic Method

This is really no different than an explicit code expression. Even so, many folks get tripped up when trying to call a generic method. The confusion comes from the fact that the code to call a generic method includes angle brackets. And as you've learned, angle brackets cause Razor to transition back to markup unless you wrap the whole expression in parentheses.

Razor @(Html.SomeMethod<AType>())
Web Forms <%: Html.SomeMethod<AType>() %>

Layouts

Layouts in Razor help maintain a consistent look and feel across multiple views within your application. If you're familiar with Web Forms, layouts serve the same purpose as Master Pages, but offer both a simpler syntax and greater flexibility.

You can use a Layout to define a common template for your site (or just part of it). This template contains one or more placeholders that the other views in your application provide content for. In some ways, it's like an abstract base class for your views.

Let's look at a very simple layout; we'll creatively call SiteLayout.cshtml:

<!DOCTYPE html>
<html>
<head><title>@ViewBag.Title</title></head>
<body>
    <h1>@ViewBag.Title</h1>
    <div id="main-content">@RenderBody()</div>
</body>
</html>

It looks like a standard Razor view, but note that there's a call to @RenderBody in the view. This is a placeholder that marks the location where views using this layout will have their main content rendered. Multiple Razor views may now take advantage of this layout to enforce a consistent look and feel.

Let's look at an example that uses this layout, Index.cshtml:

@{
    Layout = "∼/Views/Shared/SiteLayout.cshtml";
    View.Title = "The Index!";
}
<p>This is the main content!</p>

This view specifies its Layout via the Layout property. When this view is rendered, the HTML contents in this view will be placed within the DIV element, main-content of SiteLayout.cshtml, resulting in the following combined HTML markup:

<!DOCTYPE html>
<html>
<head><title>The Index!</title></head>
<body>
    <h1>The Index!</h1>
    <div id="main-content"><p>This is the main content!</p></div>
</body>
</html>

Notice that the view content, the title, and the h1 heading have all been marked in bold to emphasize that they were supplied by the view and everything else was supplied by the layout.

A layout may have multiple sections. For example, let's add a footer section to the previous Layout, SiteLayout.cshtml:

<!DOCTYPE html>
<html>
<head><title>@ViewBag.Title</title></head>
<body>
    <h1>@ViewBag.Title</h1>
    <div id="main-content">@RenderBody()</div>
    <footer>@RenderSection("Footer")</footer>
</body>
</html>

Running the previous view again without any changes will throw an exception stating that a section named Footer was not defined. By default, a view must supply content for every section defined in the layout.

Here's the updated view:

@{
    Layout = "∼/Views/Shared/SiteLayout.cshtml";
    View.Title = "The Index!";
}
<p>This is the main content!</p>

@section Footer {
    This is the <strong>footer</strong>.
}

The @section syntax specifies the contents for a section defined in the layout.

Earlier, I pointed out that by default, a view must supply content for every defined section. So what happens when you want to add a new section to a Layout? Will that break every view?

Fortunately, the RenderSection method has an overload that allows you to specify that the section is not required. To mark the Footer section as optional you can pass in false for the required parameter:

<footer>@RenderSection("Footer", false)</footer>

But wouldn't it be nicer if you could define some default content in the case that the section isn't defined in the view? Well here's one way. It's a bit verbose, but it works.

<footer>
    @if (IsSectionDefined("Footer")) {
        RenderSection("Footer");
    }
    else { 
        <span>This is the default footer.</span>   
    }
</footer>

In a later section, we'll look at an advanced feature of the Razor syntax you can leverage called Templated Razor Delegates to implement an even better approach to this.

ViewStart

In the preceding examples, each view specified its layout page using the Layout property. For a group of views that all use the same layout, this can get a bit redundant and harder to maintain.

The _ViewStart.cshtml page can be used to remove this redundancy. The code within this file is executed before the code in any view placed in the same directory. This file is also recursively applied to any view within a subdirectory.

When you create a default ASP.NET MVC 3 project, you'll notice there is already a _ViewStart.cshtml file in the Views directory. It specifies a default Layout.

@{
    Layout = "∼/Views/Shared/_Layout.cshtml";
}

Because this code runs before any view, a view can override the Layout property and choose a different one. If a set of views share common settings, the _ViewStart.cshtml file is a useful place to consolidate these common view settings.

..................Content has been hidden....................

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