Skip to content

09 - Razor Pages - Views

Passing data

Loosely typed (ViewData)

  • ViewData - collection of data
  • Accessible both in code and in views
    • ViewData – string keys based dictionary (Dict<string,object>)
    • ViewData["key"] = someObject;
  • No intellisense support, needs casting (except strings)

Razor Syntax

  • Razor is markup syntax for embedding server based code into web pages.
  • Razor syntax – Razor markup, C# code and HTML
  • Default language in razor is HTML
  • @ symbol is used to transition from HTML into C#
  • Razor expressions – any output is rendered to html output
    • Implicit – generally spaces are not allowed
      <div>@DateTime.Now</div>
      <div>@DoSomething("Hello", "World")</div>
    • Explicit - @(…C#...) - spaces are ok
      <div>@(DateTime.Now - TimeSpan.FromDays(7))</div

Expression encoding

  • C# expressions in Razor are converted to string (.ToString()) and html encoded
  • If C# expressions evaluates to IHtmlContent, then it is not encoded and rendered directly
  • Use html Raw helper to write out unencoded content
    @Html.Raw("<span>Hello World</span>")

Razor code blocks

  • @{ … c# statement; .... }
  • Default language in code block is C#
  • Using html inside code block transitions language back to html
  • Explicit transition to html

    • Use razor <text></text> tags
    1
    2
    3
    4
    @{
        var inCSharp = true;
        <p>Now in HTML, was in C# @inCSharp</p>
    }
    
    • Single line transition - @:
    1
    2
    3
    4
    5
    @for (var i = 0; i < people.Length; i++)
    {
        var person = people[i];
        @:Name: @person.Name
    }
    

Control structures

Conditionals @if, else if, else @switch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@if (value % 2 == 0)
{
    <p>The value was even</p>
}
else if (value >= 1337)
{
    <p>The value is large.</p>
}
else
{
    <p>The value was not large and is odd.</p>
}

Looping @for @foreach @while @do while

Compound @using

1
2
3
4
5
6
7
8
@using (Html.BeginForm())
{
    <div>
        email:
        <input type="email" id="Email" name="Email" value="" />
        <button type="submit"> Register </button>
    </div>
}

Comments

Razor supports C# and HTML comments.

1
2
3
4
5
@{
    /* C# comment. */
    // Another C# comment.
}
<!-- HTML comment -->

Razor comments @* …. *@

1
2
3
4
5
6
7
@*
 @{
     /* C# comment. */
     // Another C# comment.
 }
 <!-- HTML comment -->
*@

Razor view directives

A directive will typically change the way a page is parsed or enable different functionality within your Razor page.

@page
@using
@model
@inherits
@inject
@functions
@section

@using, @model, @inject, @section

  • @using System.IO
    adds using to the generated code
  • @model SomeModelType
    public class _Views_Test_cshtml : RazorPage< SomeModelType>
  • @inject
    Enables you to inject a service from your service container into your Razor page for use
  • @section
    Used in conjunction with the layout page to enable views to render content in different parts of the rendered HTML page

@function

@functions { // C# Code }

1
2
3
4
5
6
7
8
@functions {
    public string GetHello()
    {
        return "Hello";
    }
}

<div>From method: @GetHello()</div> 

Layout

Most web apps have a common layout that provides the user with a consistent experience as they navigate from page to page.

Placeholder

Razor pages layout

  • Default layout is located at Pages\Shared\_Layout.cshtml
  • Specifying an layout

    • Can use partial name or full path
    1
    2
    3
    @{
        Layout = "_Layout";
    }
    
  • Every layout must call RenderBody()
    Wherever RenderBody() is called, contents of the view will be rendered.

Section

Defining placeholder in layout file @RenderSection("Scripts", required: false)

Then define the section in view:

1
2
3
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Shared directives

Directives can be placed in file _ViewImports.cshtml.

Supports only these:

  • @addTagHelper
  • @removeTagHelper
  • @tagHelperPrefix
  • @using
  • @model
  • @inherits
1
2
3
4
5
@using WebApp
@using WebApp.Models.AccountViewModels
@using WebApp.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Pages\_ViewImports.cshtml is shared location for all views.

Initial code

  • Place initial code in _ViewStart.cshtml
  • Included in front of every page
  • Hierarchical, like _ViewImports
  • These are included in order, starting from the /Pages
1
2
3
@{
    Layout = "_Layout";
}

Partial views

A partial view is a view that is rendered within another view. The HTML output generated by executing the partial view is rendered into the calling (or parent) view.

Partial views do not include _ViewStart.cshtml

Calling an partial view (returns an IHtmlString):

  • @Html.Partial(“_SomePartialView")
  • @await Html.PartialAsync("_SomePartialViewWithAsyncCode")
  • <partial name="_PartialName" />

Referencing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Uses a view in current folder with this name
// If none is found, searches the Shared folder
@Html.Partial("ViewName")

// A view with this name must be in the same folder
@Html.Partial("ViewName.cshtml")

// Locate the view based on the application root
// Paths that start with "/" or "~/" refer to the application root
@Html.Partial("~/Pages/Folder/ViewName.cshtml")
@Html.Partial("/Pages/Folder/ViewName.cshtml")

// Locate the view using relative paths
@Html.Partial("../Account/LoginPartial.cshtml")

Accessing data

  • Receives a copy of parents ViewData (not persisted)
  • You can pass an instance of ViewDataDictionary
    @Html.Partial("PartialName", customViewData)
  • You can pass an ViewModel (declared with @model in partial)
    @Html.Partial("PartialName", Model.ContactType)
  • You can pass both an ViewModel and an instance of ViewDataDictionary
    @Html.Partial("ArticleSection", sectionModel, new ViewDataDictionary(this.ViewData) { { "index", index } })
  • You can create new ViewDataDictionary and include existing viewData into it
    new ViewDataDictionary(this.ViewData) { { "index", index } }

Tag helpers

  • Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.
  • There are many built-in Tag Helpers for common tasks - such as creating forms, links, loading assets and more - and even more available in public GitHub repositories and as NuGet packages.
  • Tag Helpers are authored in C#, and they target HTML elements based on element name, attribute name, or parent tag.
  • Tag helpers do not replace Html helpers – there is not a Tag helper for every Html helper.

<form> helpers #1

  • Asp-action
  • Asp-all-route-data
  • Asp-antiforgery
  • Asp-area
  • Asp-controller
  • Asp-fragment
  • Asp-route
  • Asp-route-<parameter name>
1
2
3
4
5
6
 <form 
    asp-controller="Account" 
    asp-action="Login" 
    asp-route-returnurl="@ViewData["ReturnUrl"]" 
    method="post" 
    class="form-horizontal">
1
<form method="post" class="form-horizontal" action="/Account/Login">

<form> helpers #2

  • Asp-controller="<Controller Name>"
  • Asp-action="<Action Name>"
    Forms target is constructed out of controller and action tag helpers
  • Asp-route="<Route Name from routing table>"
    Forms target is constructed using routing table
  • Asp-route-<parameter name>
    Parameter name is added to forms target (as query string)
  • Asp-antiforgery="true/false"
    Generate anti-forgery token as hidden value to form.Usually controlled by [ValidateAntiForgeryToken] attribute in Controller
1
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8O3e77kPeG5Fju-exRwNp8_5FUhPiQ-vxSyhpobWy0ORwL1QWwrZfyGSKxe-hClHCByTfSImSXgBIJ-cxSgHrvQsOLluGSIwgAFHclMpAIWaBBB8csOoiW0gS1o_bp_sQlhxrypM37B47MU8I_cfN1A" /> 

<form> helpers #3

  • Asp-all-route-data
    Give a dictionary for all route/target parameters
  • Asp-area
    Use area in route/target (usually not needed to specify explicitly)
  • Asp-fragment
    add #<value> to route/target

<div>

  • Asp-validation-summary – display validation summary in this div
    • ValidationSummary.All – property and model
    • ValidationSummary.ModelOnly – only model
    • ValidationSummary.None - none

<input> helpers #1

  • Asp-action, Asp-all-route-data, Asp-area, Asp-controller, Asp-fragment, Asp-route
  • Asp-for="<ModelExpression>"
    • Generates id and name attributes – used later in model binding
    • Sets the type attribute – based on model type and data annotations
    • Sets up client side validation asp-for="property1" becomes in generated code m=>m.property1
  • Asp-format="<format>"
    • Use to format value <input asp-for="SomeNumber" asp-format="{0:N4}"/>
  • Input tag helper does not handle collections and templates – use Html.XxxxxFor

<input> helpers #2

Input type is set based on .NET type.

.NET type Input type
Bool type="checkbox"
String type="text"
DateTime type="datetime"
Byte type="number"
Int type="number"
Single, Double type="number"

<input> helpers #3

Or use data annotations.

Attribute Input type
[EmailAddress] type="email"
[Url] type="url"
[HiddenInput] type="hidden"
[Phone] type="tel"
[DataType(DataType.Password)] type="password"
[DataType(DataType.Date)] type="date"
[DataType(DataType.Time)] type="time"

<span>

  • Asp-validation-for
    Display validation error (if there is one for this model property) in this span
1
<span asp-validation-for="LastName" class="text-danger"></span>

<label>

  • Asp-for
    Generate label for this model property
1
<label asp-for="LastName" class="col-md-2 control-label"></label>
1
<label class="col-md-2 control-label" for="FirstName">FirstName</label>

<textarea>

  • Asp-for
    Generate textarea input for this model property. Id, name, validation

<select>

  • Asp-for
    specifies the model property
  • Asp-items
    sepcifies option elements (List<SelectListItem>)
1
<select asp-for="Country" asp-items="Model.Countries"></select> 
  • You can generate option list from enums
1
  <select asp-for="EnumCountry" asp-items="Html.GetEnumSelectList<CountryEnum>()">

option group <optgroup>

The HTML <optgroup> element is generated when the view model contains one or more SelectListGroup objects.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public CountryViewModelGroup()
    {
        var NorthAmericaGroup = new SelectListGroup { Name = "NA" };
        var EuropeGroup = new SelectListGroup { Name = "EU" };

        Countries = new List<SelectListItem>{
            new SelectListItem{
                Value = "MEX",
                Text = "Mexico",
                Group = NorthAmericaGroup
            },
            new SelectListItem{
                Value = "FR",
                Text = "France",
                Group = EuropeGroup
            },
            ...

<select> multi-select

The Select Tag Helper will automatically generate the multiple = "multiple" attribute if the property specified in the asp-for attribute is an IEnumerable

1
2
3
4
5
6
7
8
9
public class CountryViewModelIEnumerable
    {
        public IEnumerable<string> CountryCodes { get; set; }

        public List<SelectListItem> Countries { get; } = new List<SelectListItem>
        {
            new SelectListItem { Value = "MX", Text = "Mexico" },
            new SelectListItem { Value = "CA", Text = "Canada" },
            ...

Collections

1
2
3
4
5
public class ToDoItem
{
    public string Name { get; set; }
    public bool IsDone { get; set; }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@model List<ToDoItem>
  @for (int i = 0; i < Model.Count; i++)
        {
            <tr>
                <td>
                    <label asp-for="@Model[i].Name"></label>
                </td>
                <td>
                    <input asp-for="@Model[i].IsDone" />
                </td>
            </tr>
        }

<a>

  • Asp-action, Asp-all-route-data, Asp-area, Asp-controller, Asp-fragment, Asp-route, Asp-route-<parameter name>
  • Asp-host
    Specify host to use in generated link (default is relative to current host)
  • Asp-protocol
    Specify protocol to use (default is current protocol)

<img>

  • Asp-append-version="<true/false>"
    Enable cache busting. Generates file version hash and appends it to source.

<script> helpers #1

1
2
3
4
5
6
 <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
        </script>
  • Asp-append-version
  • Asp-fallback-src
  • Asp-fallback-src-exclude
  • Asp-fallback-src-include
  • Asp-fallback-test
  • Asp-src-exclude
  • Asp-src-include

<script> helpers #2

  • Asp-append-version
  • Asp-fallback-src
    If asp-fallback-test is negative (no network) then fall back to this location
  • Asp-fallback-test
    Javascript functionality to test
  • Asp-fallback-src-exclude, Asp-fallback-src-include, Asp-src-exclude, Asp-src-include
    Comma separated list of sources to include or exclude
  • Asp-append-version
  • Asp-fallback-href
  • Asp-fallback-href-exclude
  • Asp-fallback-href-include
  • Asp-fallback-test-class
  • Asp-fallback-test-property
  • Asp-fallback-test-value
  • Asp-href-exclude
  • Asp-href-include
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<link rel="stylesheet" href="https://…/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/css/bootstrap.min.css"
asp-fallback-test-class="sr-only"
asp-fallback-test-property="position" 
asp-fallback-test-value="absolute"/>

<link 
rel="stylesheet" 
href="~/css/site.min.css" 
asp-append-version="true"/>

<environment>

  • Names=“comma_separated_list"
    asp.net core pre-defines following enviroments – Development, Staging, Production. Useful for branching in cshtml files.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<environment names="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
    <link rel="stylesheet" href="https://ajax.aspnetcdn.com/…/css/bootstrap.min.css"
                asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
                asp-fallback-test-class="sr-only" asp-fallback-test-property="position" 
                asp-fallback-test-value="absolute"/>
    <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true"/>
</environment>

HTML helpers

  • Tag helpers are there in addition to Html helpers.
  • Some functionality is only possible with Html helpers.
  • Html helpers generate full html tags – harder to read cshtml files, designers cant modify easily
  • Four main categories of helpers
    • Output
    • Input
    • Form
    • Link

Output

  • DisplayFor
  • DisplayForModel
  • DisplayNameFor
  • DisplayNameForModel
  • DisplayTextFor
  • LabelFor
  • LabelForModel

Input

  • EditorFor
  • TextAreaFor
  • TextBoxFor
  • DropDownFor
  • EnumDropDownFor
  • ListBoxFor
  • RadioButtonFor
  • HiddenFor
  • CheckBoxFor
  • PasswordFor

Form

  • BeginForm
  • BeginRouteForm
  • EndForm
  • AntiForgeryToken
  • HiddenFor
  • ActionLink
  • RouteLink

EditorFor

  • EditorFor(expression)
  • EditorFor(expression, additionalViewData)
  • EditorFor(expression, templateName)
  • EditorFor(expression, templateName, additionalViewData)
  • EditorFor(expression, templateName, htmlFieldName)
  • EditorFor(expression, templateName, htmlFieldName, additionalViewData)

  • Expression - lambda

1
2
3
4
5
6
<dt>
    @Html.DisplayNameFor(model => model.FirstName)
</dt>
<dd>
    @Html.DisplayFor(model => model.FirstName)
</dd>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Html.EditorFor(
    model => model.Participant.FirstName, 
    new { htmlAttributes = new { @class = "form-control" } }
)
@Html.ValidationMessageFor(
    model => model.Participant.FirstName, 
    "", 
    new { @class = "text-danger" }
)
@Html.ActionLink("Show items", "Show", new { id = 1}, 
    htmlAttributes: new { @class = "btn btn-primary", role = "button" })