03 - Razor Views
Views in ASP.NET Core MVC
- In the Model-View-Controller (MVC) pattern, the view encapsulates the presentation details of the user's interaction with the app.
- Views are HTML templates with embedded code that generate content to send to the client.
- Views use Razor syntax, which allows code to interact with HTML with minimal code or ceremony.
View files
- Views use .cshtml extension
- Are located in web project – Views folder
- Typically, each controller has its own folder within Views folder
- Typically, every action has its own view
\Views\<ControllerName>\<ActionName>.cshtml
- Shared views are in folder \Views\Shared
- In addition to action specific views there are
- partial views
- layouts,
- special view files
- ...
Specify what view file to use
- Usually just return View() or return View(viewModel) is used
- View discovery process (unless concrete view is requested)
\Views\<ControllerName>\<ActionName>.cshtml
\Views\Shared\<ActionName>.cshtml
- Returning some specific view
| return View(“ViewName”,viewModel); // cshtml extension not required
return View(“/Views/CustomViews/ViewName.cshtml”,viewModel);
|
Passing data
Two widely used methods
- Using ViewModels (DTOs) (can be cpecific objects or domain objects)
- strongly typed – intellisense, compiler errors
- strongly recommended (required in this course!)
- Using ViewBag or ViewData
- loosely typed data, no compiler support
- erros can only be dicovered during runtime
Passing data - ViewModel
return view(viewModel);
- In view file specify model class
@model ModelType
and access it with @Model
- ViewModels are strongly typed, with full IntelliSense support. Views are precompiled by default on distribution build.
| @model Domain.Person
<h2>Info</h2>
<div>
@Model.FirstName<br />
@Model.LastName<br />
</div>
|
Passing data - loosely typed
- ViewData or ViewBag - collection of data (objects)
- Accessible both in action methods and in views
- ViewData – string based dictionary
| ViewData["key"] = someObject;
|
- ViewBag – dynamic object collection
| ViewBag.otherKey = fooObject;
|
- ViewBag uses ViewData for its actual object storage.
So you can mix and match them.
| ViewData["foo"] = "bar";
ViewBag.foo = ViewBag.foo + "barbar";
|
- 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 transiton 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
foobar.ToString()
and encoded.
- If C# expressions evaluates to IHtmlContent, then it is not converted 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
| @{
var inCSharp = true;
<p>Now in HTML, was in C# @inCSharp</p>
}
|
- Explicit transition to html
- Use razor
<text></text>
tags
- Single line transition -
@:
| @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 (Html.BeginForm())
{
<div>
email:
<input type="email" id="Email" name="Email" value="" />
<button type="submit"> Register </button>
</div>
}
|
- Razor supports C# and HTML comments.
| @{
/* C# comment. */
// Another C# comment.
}
<!-- HTML comment -->
|
| @*
@{
/* C# comment. */
// Another C# comment.
}
<!-- HTML comment -->
*@
|
Razor directives
A directive will typically change the way a page is parsed or enable different functionality within your Razor page.
- @using
- @model
- @inherits
- @inject
- @functions
- @section
- @page
Directives
Vies are transformed into C# code/classes and compiled
| @{
var output = "Hello World";
}
<div>Output: @output</div>
|
Directives add some modifications into generated C# code
| public class _Views_Something_cshtml : RazorPage<dynamic>
{
public override async Task ExecuteAsync()
{
var output = "Hello World";
WriteLiteral("/r/n<div>Output: ");
Write(output);
WriteLiteral("</div>");
}
}
|
-
@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.
-
@functions { // C# Code }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | @functions {
public string GetHello()
{
return "Hello";
}
}
<div>From method: @GetHello()</div>
~~~~
~~~csharp
public class _Views_Home_Test_cshtml : RazorPage<dynamic>
{
public string GetHello()
{
return "Hello";
}
public override async Task ExecuteAsync()
{
x
Write(GetHello());
WriteLiteral("</div>\r\n");
}
...
|
Layout
Most web apps have a common layout that provides the user with a consistent experience as they navigate from page to page.

Default layout
-
Default layout is located at
Views\Shared\_Layout.cshtml
-
Specifying an layout
- Can use partial name or full path
-
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
| @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
Views\_ViewImports.cshtml
is shared location for all views
| @using WebApp
@using WebApp.Models.AccountViewModels
@using WebApp.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
Initial code
- Place initial code in
_ViewStart.cshtml
- Included in front of every view
- Hierarchical, like _ViewImports
- These are included in order, starting from the /View, then from /Controller
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
Partial tag helper.
| <partial name="_PartialName" />
<partial name="_PartialName" for="Model" view-data="ViewData"/>
<partial name="_PartialName" model="Model" view-data="ViewData"/>
|
- for
- model
- view-data
- assigns ViewDataDictionary
Older, html helper partial.
| @Html.Partial("SomePartialView")
@await Html.PartialAsync("SomePartialViewWithAsyncCode")
@{
Html.RenderPartial("SomePartialView ");
Html.RenderPartialAsync("SomePartialViewWithAsyncCode ");
}
|
Partial view discovery
| /Areas/<Area-Name>/Views/<Controller-Name>
/Areas/<Area-Name>/Views/Shared
/Views/Shared
/Pages/Shared
|
Partial views can be chained—a partial view can call another partial view if a circular reference isn't formed by the calls. Relative paths are always relative to the current file, not to the root or parent of the file.
Area
- Areas are used to organize related functionality into a group as a separate namespace (for routing) and folder structure (for views).
- Using areas creates a hierarchy for the purpose of routing by adding another route parameter, area, to controller and action.
- Effectively a separate MVC structure inside an web application
Folder structure
Typical folder structure
WebApp
| /Areas/<Area-Name>/Views/<Controller-Name>/<Action-Name>.cshtml
/Areas/<Area-Name>/Views/Shared/<Action-Name>.cshtml
/Views/Shared/<Action-Name>.cshtml
|
Area controllers
- Structure of views folder is important – compiled singly. Controllers and models can be anywhere – one dll.
- Assign controller to specific area using area attribute
| namespace MyStore.Areas.Admin.Controllers;
[Area("Admin")]
public class HomeController : Controller {
...
}
|
Area routing
Set up convention-based routing
| app.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
|
Area links
Inside the same are - no action needed, ambient value is used
To different area
| <a asp-area="Admin" asp-controller="Home" asp-action="Index">Admin</a>
|
To no area
| <a asp-area="" asp-controller="Home" asp-action="Index">Home</a>
|