The 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 includes two different view engines, the newer 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 was introduced with 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 all that syntactic noise required to write a view created friction when trying to read that view.

This request was finally answered in ASP.NET MVC 3 with the introduction of the 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.


Product Team Aside
The precursor that led to Razor started off as a prototype (by Dmitry Robsman) that attempted to preserve some of the goodness of the ASP.NET MVC approach, at the same time allowing for a simpler (one page at a time) development model.
His prototype was named Plan9, after the 1959 science fiction/horror film Plan 9 from Outer Space, considered to be one of the worst movies ever made.
Plan9 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 “Plan9” 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 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, have the .vbhtml file extension. These file extensions are important, as they signal the code language syntax to the Razor parser.


Don't OverThink It
We're about to dig into the mechanics of Razor syntax. Before we do, the best advice I can give you is to remember that Razor was designed to be easy and intuitive. For the most part, you don't have to worry about Razor syntax — just type HTML and hit the @ sign when you want to insert some code.

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. However, it may make some of you worry that ambiguities can occur. For example, what if we had the following Razor snippet?

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

In this particular case, what we hoped to output was:

<span>MyApp.Models</span>

Instead, 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 them 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 e-mail address. For example, consider the following e-mail address:

<span>[email protected]</span>

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


Note
Razor uses a very simple algorithm to determine whether something looks like an e-mail address. It's not meant to be perfect, but it handles most cases. Some valid e-mails may appear not to be e-mails, in which case you can always escape the @ sign with an @@ 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:

<li>[email protected]</li>

In this particular case, that expression seems to match an e-mail address, so Razor will print it out verbatim. But it just so happens 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>

As mentioned earlier, you can escape the @ sign with an @@ sign. This comes in handy when you need 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 an @@ sign. Thus this view becomes:

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

Fortunately, the extra parentheses and escape sequences are rarely needed. Even in very large applications these extra bits of sequences might not be used at all. Rest assured that the Razor view engine was designed with terseness in mind and that you won't have to fight it to get what you want, how you want it.

HTML Encoding

Given that there are many cases where a view is used to display user input, such as a blog post comment or a product review, 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 automatically 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 render the encoded HTML:

<span>&lt;script&gt;alert(&#39;haacked!&#39;);&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 because they want HTML to be rendered to the page. 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 username. The username comes from a Razor expression.

Using the jQuery HTML method, this message is set to be the HTML for a DOM element in the ID “message.” Even though the username is HTML encoded within the message string, there is still a potential XSS vulnerability. For example, if someone supplies the following as their username, 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>

Note
It's very important to understand the security implications of HTML and JavaScript encoding. Incorrect encoding can put both your site and your users at risk. These aspects are discussed in detail in Chapter 7.

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, because the Razor engine has special knowledge of those C# keywords.

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 that illustrate the syntax for Razor by comparing a Razor example with the equivalent example using the Web Forms view engine syntax. Each sample highlights a specific Razor concept.

Implicit Code Expression

As described previously, 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. This Web Forms syntax also automatically HTML encodes the value.

Explicit Code Expression

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 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 a special tag and is not written to the response, only its contents are written out. I personally like this approach because it makes logical sense to me. If I want to transition from code to markup, I use a tag.

Others prefer the second approach, which is a special syntax for switching from code back to plain text, though this approach works only for a single line of text at a time.

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;haacked
or
My Twitter Handle is @@haacked
Web Forms &lt;% expression %&gt; marks a codenugget.

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 it 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, it was 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", required: false)</footer>

But wouldn't it be nicer if you could define some default content if 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 Chapter 15 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.


Default Layout changes in MVC 4
When you create a new MVC 4 application using either the Internet or Intranet template, you'll get a default layout with some basic style applied. Prior to MVC 4, the design in the default templates was very Spartan — just a block of white text on a blue background.
As mentioned in Chapter 1, the default templates have been completely rewritten in MVC 4 to provide a much better visual design. In addition to simply looking better, the new HTML and CSS adapts to differing screen widths (including small mobile browsers). This adaptive design takes advantage of modern web standards such as CSS Media Queries. We'll look at how this works in detail in Chapter 15.

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 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 shares common settings, the _ViewStart.cshtml file is a useful place to consolidate these common view settings. If any view needs to override any of the common settings, the view can set those values to another value.

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

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