Razor

Razor is the new syntax/view engine that replaces the old Web Forms (ASPX) syntax/view engine. It is simpler and easier to read.

Razor pages have file extension *.cshtml or *.vbhtml, depending on which language you use. These notes are all based on the C# (.cshtml) syntax.

Template

Razor views are templates that are filled in with data to produce web pages.

Literal strings are plain HTML. C# code starts with an "@".


@{ var message = "Good morning"; }
<p>Message says @message.</p>


@{ var student = new Student("Bob", 19); }
<p>Student name is @student.Name and age is @student.Age.</p>
<p>Student is in @student.CountClasses() classes.</p>

The Model and the ViewBag are both available in the view.

Comments


@* comments here *@


@{
    //more comments
    /* multiline comments */
}

Code Block

These lines are executed. Nothing is automatically added to the output.


@{
    //proper C# code;
}

Inline Expressions

These results are added directly to the output.

Implicit Code Expressions

Plain text @... Plain text

Explicit Code Expressions

Plain text @(...) Plain text

Email Address: the Razor Engine assumes text formatted as "a@b.c" is an email address, and will not implicitly interpret it as a code expression.

Escape

Escape "@" (at sign) with another "@".

@@Plain text

Explicitly specify string literals:

@:Plain text
New View

The new view dialog in Visual Studio:

View engine: Razor

Strongly-Typed View: you can set the model type for the view

Scaffold Template: the view can be generated with some default code to get you started
    

HTML Paths

"~" (tilda) at the beginning of an HTML path means the root of the web page.
Ex: "~/Views/Contact/Index.cshtml"

If you're path does not start with a "~", it is an absolute path.
Using relative paths is highly recommended
Shortcuts

Add View

In Visual Studio, right-click in the action method, select "Add View".
Or, in the action method, type Ctrl-M + Ctrl-V.

This will add a view to Project/Views/<controller name>/<action name>.cshtml
Layout

_ViewStart

File ~/Views/ViewStart.cshtml will run before each view, by default.
This is where the environment variable "Layout" is set to its default value of "~/Views/Shared/_Layout.cshtml".

Layout

The environment variable "Layout" is a string filepath to the layout that should be used with the current view.

Use no layout:

@model MyModel
@{
    Layout = null;
    //or
    Layout = "";
}
Controls

The Razor Engine can usually tell when to switch between C# code and HTML in these code blocks.

When it sees an HTML tag, it knows to switch to HTML interpretation.
If you try to start with plain text, it will give an error:

@for(var i=0; i<10; i++)
{
    Plain Text causes error
    @:Plain Text does not cause error
    <p>Line @i</p>
}

For


<body>
    @for(var i=0; i<10; i++)
    {
        <p>Line @i</p>
    }
</body>

Foreach


<body>
    @foreach(var item in list)
    {
        <p>Item @item.Name</p>
    }
</body>

If Else


<body>
    @if(age < 50)
    {
        <p>the age is @age</p>
    }
</body>


<body>
    @if(hour < 12)
    {
        <p>It is morning</p>
    }
    else
    {
        <p>It is afternoon</p>
    }
</body>

Switch


<body>
    @switch(x)
    {
        case 0: y = "text"; break;
        case 1: y = "other text"; break;
        default: y = "";
    }
    <p>@y</p>
</body>

Functions

@Helpers

@Helpers are functions that do not return a value. They output directly to the page.


@helper DisplayPrice(decimal price) 
{
    if(price == 0)
    {
        <span>Free!</span>
    }
    else
    {
        <span>@String.Format("{0:C2}", price)</span>
    }
}
@foreach(Product x in list)
{
    <p>@x.Name: @DisplayPrice(x.Price)</p>
}

If you call a helper from within a helper, always use the "@" symbol. Even if the syntax highlighter indicates that the method call is recognized as such, it'll get skipped.

@helper A()
{
    @B();
}
@helper B()
{
    @:Reached B
}

Note that you cannot code-step through a @helper (at least in VS2015), but the code does run.

Functions

Functions do return values.


@functions 
{
    string FormatPrice(decimal price)
    {
        if(price == 0)
            return "Free!";
        return String.Format("{0:C2}", price);
    }
}
@foreach(Product x in list)
{
    <p>@x.Name: @FormatPrice(x.Price)</p>
}

Global

You can create global helpers and functions (usable in any View) by adding them to a *.cshtml file in folder Project/App_Code.

Project/App_Code/GlobalHelpers.cshtml

@helper DisplayAuthor(Author author) {
    <a href="@Url.Action("Details", "Author")">@author.LastName</a>
}

@functions {
    public static string SayTest() {
        return "test";
    }
}

Any view file:

@GlobalHelpers.DisplayAuthor(book.Authors.First())

@GlobalHelpers.SayTest()

Note that the helper/function is accessed based the name of the file it is in.


Sections

When RenderSection("SectionName") is called, this is the what is rendered:

@section SectionName {
    //stuff
}
Model

Strongly Typed

A strongly-typed view expects a particular data type to be passed in as its model. Declare the data type at the top of the file, like this:


@model DataType

Naming Convention

The variable "Model" is automatically available within your view.

When using a lambda expression, do not use "Model". Use something like "model" or "m" instead. It can cause problems to step on the name of the actual model variable.
Strings

Literals

String literals are added to the output as they are.

Some plain text.
<p>Some HTML tags.</p>

Output string literals:

@Response.Write("text")
@Html.Raw("text")

HtmlHelper

Everything the HtmlHelper outputs is HTML encoded. This protects you from cross-site scripting attacks.

HtmlHelper methods automatically operate on the Model.

Link

Generate a link to the specified action:

@Html.ActionLink(text, actionName)
@Html.ActionLink(text, actionName, new { id = model.Id }) //pass additional information
@Html.ActionLink(text, actionName, controllerName, new { id = model.Id }, null) //link to a different controller

Strings

Generate the display name of the model field based on the field's attributes:

@Html.DisplayNameFor(model => model.Name)

Generate the value of the model field, correctly formatted based on field type:

@Html.DisplayFor(model => model.Name)

Form


@using(Html.BeginForm())
{
    <input type="submit" value="Submit" />
}
This form will default to posting back to the current URL, with current URL parameters included.
"BeginForm" has nothing to dispose at the end of this "using" block, it just knows that's when to close the form tag.

BeginForm overloads:

@using(Html.BeginForm("Action")) { }
@using(Html.BeginForm("Action", "Controller")) { }
@using(Html.BeginForm("Action", "Controller", FormMethod.Post)) { }
@using(Html.BeginForm("Action", "Controller", FormMethod.Post, new { id="formId", name="formName", data_custom="becomes data-custom attribute" })) { }

Generate a label for the model field, based on field attributes:

@Html.LabelFor(model => model.Name)

Generate an input control for the model field, correctly formatted based on field type:

@Html.EditorFor(model => model.Name)

Generate a validation message section for the model field, based on field attributes:

@Html.ValidationMessageFor(model => model.Name)

Generate a validation section for messages not associated with a particular field:

@Html.ValidationSummary(true)
Passing a "false" argument means that every validation message will be displayed in this section.

Generate a hidden form field for the model field:

@Html.HiddenFor(model => model.Name)

SubRequest

In this example, there is information you want to display as part of your global Layout, regardless of what Model the View is using.

"Html.Action" will generate an entirely new Request that will result in a new Partial View and Model. The results of all this will be included in that View that makes the SubRequest.

This all happens during the current HTTP Request - there is not a new HTTP Request sent from the user's browser.


<!-- In View -->
<div>
    @Html.Action("MyAction", "MyController")
</div>

//in controller
[ChildActionOnly] //this action cannot be called directly with an HTTP Request
public ActionResult MyAction()
{
    var model = GetModel();
    return PartialView("partialViewName", model);
}

Partial

Returns partial view result as a string:

<tag>
    @Html.Partial("ViewName", model)
</tag>

Returns nothing, sends results directly to response object:

<tag>
@{
    Html.RenderPartial("ViewName", model);
}
</tag>
AJAX

AJAX provides asynchronous HTTP Requests.

Razor includes an AJAX helper called "Ajax".

Unobtrusive

All ASP.Net MCV Ajax uses the "Unobtrusive JavaScript" approach to JavaScript.

This means that javascript is not mixed into HTML elements (ex: <a onclick="handleClick()" />).

It also means that even if the client has javascript disabled in their browser, you're web page will still function.

Example of form tag generated by "Ajax.BeginForm":

    <!-- these are "Data Dash Attributes" -->
    <!-- Data Dash Attributes are private data for the application, and are ignored by the browser -->
    <form action="/" data-ajax="true" data-ajax-method="get" data-ajax-mode="replace" data-ajax-update="#countryList" method="post">
    </form>
If javascript is enable, this form will have events attached to it, based on the "data-ajax" attributes, so that this request will be sent as an AJAX request.
If javascript is not enabled, this request will still run as a normal form submission, and the entire page will reload with the new data.

Form validation works the same way.

Link

Generates a link for an asynchronous request that will update the screen instead of navigating to a new page.


@Ajax.ActionLink(...)

Form

Example of using AJAX to load search results without reloading the entire page:

//inside a *.cshtml page
@using(Ajax.BeginForm(new AjaxOptions { 
    HttpMethod="get",
    InsertionMode=InsertionMode.Replace, //the results of this request will replace a section of the current HTML page
    UpdateTargetId="countryList"         //the HTML element whose contents will be replaced has id "countryList"
    }))
{
    <input type="search" name="searchTerm"/>
    <input type="submit" value="Search by Name"/>
}
<div id="countryList">
    @foreach(MyModel item in Model)
    {
        //render item
    }
</div>
Because the AJAX results will be inserted directly into the current page, make sure that the AJAX results come from a Partial View.

Distinguish AJAX request within controller:

//in controller
public ActionResult MyMethod(MyModel model)
{
    ...
    if(Request.IsAjaxRequest()) //checks an HTTP Header
    {
        return PartialView("_MyView", model);
    }
    return View(model);
}

Directives

Model

Make a strongly-typed view by specifying the expected model.


//at top of *.cshtml view file
@model MyProject.Models.MyModel

//to access the model
<h1>@Model.MyAttribute</h1>
HTML Helpers

Simple, a method that returns a string. They are used to abstract standard HTML tags.

Assembly: System.Web.Mvc.Html

Basics


Html.ActionLink(...)
Html.BeginForm(...) and Html.EndForm(...)
Html.Hidden(...)
Html.Password(...)
Html.CheckBox(...) and Html.CheckBoxFor(...)
Html.DropDownList(...) and Html.DropDownListFor(...)
Html.ListBox(...) and Html.ListBoxFor(...)
Html.RadionButton(...) and Html.RadioButtonFor(...)
Html.TextArea(...) and Html.TextAreaFor(...)
Html.TextBox(...) and Html.TextBoxFor(...)

The "xFor" versions are strongly-typed (updates when the object changes), the others are weakly-typed. Both render to the same HTML.

Weakly typed:

<label for="FirstName">First Name:</lable>@Html.TextBox("FirstName")

Strongly typed:

@model Student

<label for="FirstName">First Name:</lable>@Html.TextBox(m => m.FirstName)
/*
In the lambda, "m" is the model, the Student object that was passed to this view.
Do not call it "model" in the lambda, the variable name will conflict with the implicit "model" variable.
*/

Custom

You can make your own Helpers with static methods.


namespace MyApp.Helpers
{
    public static class MyHelpers
    {
        public static string Label(string target, string text)
        {
            return String.Format("<label for='{0}'>{1}</label>", target, text);
        }
    }
}
...
@MyHelpers.Label("target", "text")

You can also use extension methods on the Html class.


namespace MyApp.Helpers
{
    public static class LabelExtensions
    {
        public static string MyLabel(this HtmlHelper helper, string target, string text)
        {
            return String.Format("<label for='{0}'>{1}</label>", target, text);
        }
    }
}
...
@Html.MyLabel("target", "text")