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;
- ViewData – string keys based dictionary (
- 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
- Implicit – generally spaces are not allowed
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
@{ var inCSharp = true;
<p>Now in HTML, was in C# @inCSharp</p>
}- Single line transition -
@:
@for (var i = 0; i < people.Length; i++) { var person = people[i]; @:Name: @person.Name }
- Use razor
Control structures
Conditionals
@if, else if, else
@switch
@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
@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.
@{ /* C# comment. */ // Another C# comment. }
<!-- HTML comment -->
Razor comments @* …. *@
@* @{ /* 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 }
@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.
Razor pages layout
-
Default layout is located at
Pages\Shared\_Layout.cshtml
-
Specifying an layout
- Can use partial name or full path
@{ Layout = "_Layout"; }
-
Every layout must call
RenderBody()
WhereverRenderBody()
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:
@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
@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
@{
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
// 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>
<form
asp-controller="Account"
asp-action="Login"
asp-route-returnurl="@ViewData["ReturnUrl"]"
method="post"
class="form-horizontal">
<form method="post" class="form-horizontal" action="/Account/Login"></form>
<form>
helpers #2
Asp-controller="<Controller Name>"
Asp-action="<Action Name>"
Forms target is constructed out of controller and action tag helpersAsp-route="<Route Name from routing table>"
Forms target is constructed using routing tableAsp-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
<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 parametersAsp-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 divValidationSummary.All
– property and modelValidationSummary.ModelOnly
– only modelValidationSummary.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 codem=>m.property1
Asp-format="<format>"
- Use to format value
<input asp-for="SomeNumber" asp-format="{0:N4}"/>
- Use to format value
- 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
<span asp-validation-for="LastName" class="text-danger"></span>
<label>
Asp-for
Generate label for this model property
<label asp-for="LastName" class="col-md-2 control-label"></label>
<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>
)<select asp-for="Country" asp-items="Model.Countries"></select>
-
You can generate option list from enums
<select asp-for="EnumCountry" asp-items="Html.GetEnumSelectList<CountryEnum>()"></select>
option group <optgroup>
The HTML <optgroup>
element is generated when the view model contains one or more SelectListGroup objects.
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
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
public class ToDoItem
{
public string Name { get; set; }
public bool IsDone { get; set; }
}
@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>
}</ToDoItem
>
<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
<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 locationAsp-fallback-test
Javascript functionality to testAsp-fallback-src-exclude
,Asp-fallback-src-include
,Asp-src-exclude
,Asp-src-include
Comma separated list of sources to include or exclude
<link>
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
<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.
<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
Link
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
<dt>@Html.DisplayNameFor(model => model.FirstName)</dt>
<dd>@Html.DisplayFor(model => model.FirstName)</dd>
@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" })