1.创建视图
右键单击Views
文件夹-添加–新建文件夹-名称复数Movies
。
右键单击刚刚新建的Views/Movies
文件夹-添加–新建项-选择合适的视图选项-名称Index.cshtml
–添加。
2.View()
帮助方法
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
//隐式返回视图,隐式传递或不传递模型对象
return View();
//隐式返回视图,显式传递模型对象
return View(Orders);
//显式返回视图,隐式传递或不传递模型对象
return View("Orders");
//显式返回视图,显式传递模型对象
return View("Orders", Orders);
2.1视图发现
/Areas/<Area-Name>/Views/<Controller-Name>/<Action-Name>.cshtml
/Areas/<Area-Name>/Views/Shared/<Action-Name>.cshtml
/Views/Shared/<Action-Name>.cshtml
/Pages/Shared/<Action-Name>.cshtml
3.强类型数据 (viewmodel)
在控制器和视图之间传递数据的模型通常称为 viewmodel。
一般情况下,viewmodel
是Plain Old CLR Object
(POCO
),含有少量或没有已定义的行为(方法)。通常,viewmodel
类要么存储在 Models
文件夹中,要么存储在应用根目录处的单独 ViewModels
文件夹中。
控制器操作通过View()
帮助方法显式将viewmodel
类型的实例传递给此操作的视图。
视图文件中@model
指令用于定义viewmodel
的类型,@Model
指令用于使用viewmodel
类型的实例。
namespace WebApplication1.ViewModels
{
public class Address
{
public string Name { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
var viewModel = new Address()
{
Name = "Microsoft",
Street = "One Microsoft Way",
City = "Redmond",
State = "WA",
PostalCode = "98052-6399"
};
return View(viewModel);
}
@model WebApplication1.ViewModels.Address
<h2>Contact</h2>
<address>
@Model.Street<br>
@Model.City, @Model.State @Model.PostalCode<br>
<abbr title="Phone">P:</abbr> 425.555.0100
</address>
4.弱类型数据
在…之间传递数据 | 示例 |
---|---|
控制器和视图 | 用数据填充下拉列表。 |
视图和布局视图 | 从视图文件设置布局视图中的 <title> 元素内容。 |
分部视图和视图 | 基于用户请求的网页显示数据的小组件。 |
4.1 ViewData
ViewData
是通过 string
键访问的 ViewDataDictionary
对象。
ViewData
通过View()
帮助方法传递数据时,是隐式地传递数据。
public IActionResult SomeAction()
{
ViewData["Greeting"] = "Hello";
ViewData["Address"] = new Address()
{
Name = "Steve",
Street = "123 Main St",
City = "Hudson",
State = "OH",
PostalCode = "44236"
};
return View();
}
@{
// Since Address isn't a string, it requires a cast.
var address = ViewData["Address"] as Address;
}
@ViewData["Greeting"] World!
<address>
@address.Name<br>
@address.Street<br>
@address.City, @address.State @address.PostalCode
</address>
4.2 [ViewData]
特性
使用 ViewDataDictionary
的另一种方法是 ViewDataAttribute
。
使用 [ViewData]
特性的控制器属性将其值存储在字典中并从中进行加载。
public class HomeController : Controller
{
[ViewData]
public string Title { get; set; }
public IActionResult About()
{
Title = "About Us";
ViewData["Message"] = "Your application description page.";
return View();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
4.3 ViewBag
ViewBag
是 Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData
对象,可提供对存储在 ViewData
中对象的动态访问权限。
ViewBag
不需要强制转换,因此使用起来更加方便。
public IActionResult SomeAction()
{
ViewBag.Greeting = "Hello";
ViewBag.Address = new Address()
{
Name = "Steve",
Street = "123 Main St",
City = "Hudson",
State = "OH",
PostalCode = "44236"
};
return View();
}
@ViewBag.Greeting World!
<address>
@ViewBag.Address.Name<br>
@ViewBag.Address.Street<br>
@ViewBag.Address.City, @ViewBag.Address.State @ViewBag.Address.PostalCode
</address>
5.布局(Layout
)视图
5.1布局
按照约定,ASP.NET Core 应用的默认布局名为 _Layout.cshtml
。
应用可以没有布局,也可以定义多个布局,其中不同的视图指定不同的布局。
//占位
@RenderBody()
5.2 _ViewStart.cshtml
_ViewStart.cshtml
文件通常放置在Views
文件夹中。
需要在每个视图之前运行的代码应放在 _ViewStart.cshtml
文件中。
通过在_ViewStart.cshtml
文件中设置Layout
属性来指定所有视图都将使用 _Layout.cshtml
布局。
@{
Layout = "_Layout";
}
5.3 _ViewImports.cshtml
_ViewImports.cshtml
文件通常放置在Views
文件夹中。
可在_ViewImports.cshtml
文件中指定由许多视图共享的Razor
指令,这些指令用来导入命名空间和使用依赖注入。
@addTagHelper
@removeTagHelper
@tagHelperPrefix
@using
@model
@inherits
@inject
@namespace
5.4内容根目录和Web根目录
内容根目录{content root}
默认为项目的根目录。
Web
根目录路径默认为 {content root}/wwwroot
。
在 Razor.cshtml
文件中,~/
指向 Web
根目录。
但是,在分部视图中,以波形符斜杠 (~/
) 或斜杠 (/
) 开头的路径指向项目的根目录。
5.5CSS
隔离
若要为 .cshtml
视图文件添加限定范围的 CSS
样式,请将 CSS
样式置于与 .cshtml
视图文件同目录且名称相同的 .cshtml.css
文件中。 比如,Index.cshtml.css
文件只应用于 Index.cshtml
视图文件的 CSS
样式。
重写的 CSS 样式作为静态资产 {APP ASSEMBLY}.styles.css
进行捆绑和生成。占位符 {APP ASSEMBLY}
是项目名称。指向捆绑 CSS 样式的链接放置在应用的布局中。
<link rel="stylesheet" href="{APP ASSEMBLY}.styles.css" />
5.6节(Section
)
布局可以通过调用 RenderSection
来选择引用一个或多个节。节提供一种方法来组织某些页面元素应当放置的位置。required
指定此节是必需还是可选的。
//布局视图文件(同步)
@RenderSection("Scripts", required: false)
//布局视图文件(异步)
@await RenderSectionAsync("Scripts", required: false)
//视图文件调用分部视图(异步HTML帮助程序)
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
//视图文件调用分部视图(分部标记帮助程序)
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
//视图文件直接调用
@section Scripts {
<script type="text/javascript" src="~/scripts/main.js"></script>
}
6.分部(Partial
)视图
分部视图的文件名通常以下划线 (_
) 开头,名称中带Partial
字符的.cshtml
文件。
有两种方法可引用分部视图:分布标记帮助程序(Partial Tag Helper
)和异步 HTML 帮助程序(Asynchronous HTML Helper
)。
6.1分部标记帮助程序
分部标帮助程序会异步呈现内容并使用类似 HTML 的语法:
<partial name="_PartialName" />
6.2 for
属性
使用 for
属性,将模型传递给分部视图进行绑定。
<partial name="_ProductPartial" for="Product">
using Microsoft.AspNetCore.Mvc.RazorPages;
using TagHelpersBuiltIn.Models;
namespace TagHelpersBuiltIn.Pages
{
public class ProductModel : PageModel
{
public Product Product { get; set; }
public void OnGet()
{
Product = new Product
{
Number = 1,
Name = "Test product",
Description = "This is a test product"
};
}
}
}
6.3model
属性
model
属性分配模型实例,以传递到分部视图。特性 model
不能与 for
特性一起使用。
<partial name="_ProductPartial"
model='new Product { Number = 1, Name = "Test product", Description = "This is a test" }'>
//HTML帮助程序
//product是Product的实例
@await Html.PartialAsync("_ProductPartial", product)
6.4view-data
属性
view-data
属性分配 ViewDataDictionary
以传递给分部视图。
@{
ViewData["IsNumberReadOnly"] = true;
}
<partial name="_ProductViewDataPartial" for="Product" view-data="ViewData">
6.5异步HTML帮助程序
使用异步HTML帮助程序时,可以使用PartialAsync
方法,前面需要@await
修饰。
@await Html.PartialAsync("_PartialName")
另外,使用异步HTML帮助程序时,还可以使用RenderPartialAsync
方法,前面需要@{ await }
修饰。
由于 RenderPartialAsync
流式传输呈现的内容,因此在某些情况下它可提供更好的性能。
@{
await Html.RenderPartialAsync("_AuthorPartial");
}
6.6分部视图发现
如果按名称(无文件扩展名)引用分部视图,则按所述顺序搜索以下位置:
/Areas/<Area-Name>/Views/<Controller-Name>
/Areas/<Area-Name>/Views/Shared
/Views/Shared
/Pages/Shared
7.Razor语法
Razor语法 是一种标记语法(以 @
符号开头),用于将基于 .NET 的代码嵌入到HTML网页中。
Razor语法通常用于 .cshtml
文件 和 .razor
组件文件。
7.1注释
//C#注释和HTML注释
@{
/* C# comment */
// Another C# comment
}
<!-- HTML comment -->
//Razor注释
@*
@{
/* C# comment */
// Another C# comment
}
<!-- HTML comment -->
*@
7.2转义字符
//转义@符号
<p>@@Username</p>
//转义Razor关键字
@(functions)
//转义C# Razor关键字
@(@case)
//邮件的@符号不会被认为转义字符
<a href="mailto:Support@contoso.com">Support@contoso.com</a>
7.3隐式Razor表达式
//隐式Razor以@开头,后跟C#代码
@DateTime.Now
//隐式Razor不能包含空格,但await除外
<p>@await DoSomething("hello", "world")</p>
//隐式Razor不能包含C#泛型,因为<>字符会被解释为HTML标记。
<p>@GenericMethod<int>()</p>
7.4显式Razor表达式
//显式Razor由@符号和圆括号组成
//显式Razor可以包含空格
<p>Last week this time: @(DateTime.Now - TimeSpan.FromDays(7))</p>
//显式Razor可以包含C#泛型
<p>@(GenericMethod<int>())</p>
//如果不使用显式表达式,<p>Age@joe.Age</p>会被视为电子邮件地址
@{
var joe = new Person("Joe", 33);
}
<p>Age@(joe.Age)</p>
7.5表达式编码
计算结果为字符串的 C# 表达式采用 HTML 编码。 计算结果为 IHtmlContent
的 C# 表达式直接通过 IHtmlContent.WriteTo
呈现。 计算结果不为 IHtmlContent
的 C# 表达式通过 ToString
转换为字符串,并在呈现前进行编码。
@("<span>Hello World</span>")
//被HTML编码后
<span>Hello World</span>
//最终在浏览器中显式为纯文本
<span>Hello World</span>
对未经审查的用户输入使用 HtmlHelper.Raw
会带来安全风险。用户输入可能包含恶意的 JavaScript
或其他攻击。审查用户输入比较困难。应避免对用户输入使用 HtmlHelper.Raw
,非用户输入可以使用HtmlHelper.Raw
。
@Html.Raw("<span>Hello World</span>")
//最终<span>会被作为html标签呈现
<span>Hello World</span>
7.6Razor代码块
Razor 代码块以 @
开始,并括在 {}
中。
表达式与代码块的共同点是:里面带HTML标签的HTML都会被呈现,HTML编码除外。区别在于:表达式里面的C#代码会被呈现,而代码块里面的C#代码不会被呈现。
//一个视图中的代码块和表达式共享相同的作用域并按顺序进行定义
@{
var quote = "The future depends on what you do today. - Mahatma Gandhi";
}
<p>@quote</p>
@{
quote = "Hate cannot drive out hate, only love can do that. - Martin Luther King, Jr.";
}
<p>@quote</p>
//输出
<p>The future depends on what you do today. - Mahatma Gandhi</p>
<p>Hate cannot drive out hate, only love can do that. - Martin Luther King, Jr.</p>
@{
var inCSharp = true;
<p>Now in HTML, was in C# @inCSharp</p>
}
//输出
<p>Now in HTML, was in C# True</p>
//本地函数
@{
void RenderName(string name)
{
<p>Name: <strong>@name</strong></p>
}
RenderName("Mahatma Gandhi");
RenderName("Martin Luther King, Jr.");
}
//输出
<p>Name: <strong>Mahatma Gandhi</strong></p>
<p>Name: <strong>Martin Luther King, Jr.</strong></p>
//如果没有HTML或Razor标记,则会发生Razor运行时错误,可以使用<text>标签输出不带HTML标签的HTML。
//仅呈现<text>标记之间的内容,内容之间仅显式一个空格,多余的空格以及<text>和</text>标记之前或之后的空格都不会显示在HTML输出中。
//<text>标签内的html标签会被作为html标签呈现
@{
<text> Hello World </text>
}
//输出
Hello World
//另外还可以使用@:符号输出整个行中除了@:符号以外的后面的不带HTML标签的HTML。
//@:内的html标签会被作为html标签呈现
//与<text>标签的区别在于@:仅支持单行内容,<text>标签支持多行内容
@{
@: Hello World
}
//输出
Hello World
7.7 @lock
语句
@lock (SomeLock)
{
// Do critical section work
}
7.8 @using
语句
@using (Html.BeginForm())
{
<div>
Email: <input type="email" id="Email" value="">
<button>Register</button>
</div>
}
7.9条件语句@if, else if, else,
and @switch
@if (value % 2 == 0)
{
<p>The value was even.</p>
}
//else 和 else if 不需要 @ 符号。
@if (value % 2 == 0)
{
<p>The value was even.</p>
}
else if (value >= 1337)
{
<p>The value is large.</p>
}
else
{
<p>The value is odd and small.</p>
}
@switch (value)
{
case 1:
<p>The value is 1!</p>
break;
case 1337:
<p>Your number is 1337!</p>
break;
default:
<p>Your number wasn't 1 or 1337.</p>
break;
}
7.10迭代语句@for, @foreach, @while, and @do while
@{
var people = new Person[]
{
new Person("Weston", 33),
new Person("Johnathon", 41),
...
};
}
@{ var i = 0; }
@while (i < people.Length)
{
var person = people[i];
<p>Name: @person.Name</p>
<p>Age: @person.Age</p>
i++;
}
@{ var i = 0; }
@do
{
var person = people[i];
<p>Name: @person.Name</p>
<p>Age: @person.Age</p>
i++;
} while (i < people.Length);
@for (var i = 0; i < people.Length; i++)
{
var person = people[i];
<p>Name: @person.Name</p>
<p>Age: @person.Age</p>
}
@foreach (var person in people)
{
<p>Name: @person.Name</p>
<p>Age: @person.Age</p>
}
7.11异常语句@try, catch, finally
@try
{
throw new InvalidOperationException("You did something invalid.");
}
catch (Exception ex)
{
<p>The exception message: @ex.Message</p>
}
finally
{
<p>The finally statement.</p>
}
8.Razor
指令
8.1@attribute
指令
@attribute
指令将给定的特性添加到生成的视图的类中。
//添加[Authorize]特性
@attribute [Authorize]
8.2@code
指令
仅适用于Razor组件(.razor
)。
使用一个或多个 @code
代码块,可以将 C# 成员 (字段、属性和方法) 添加到Razor组件。
对于Razor组件,@code
是 @functions
的别名,建议优先使用@code
。
@code {
// C# members (fields, properties, and methods)
}
8.3 @functions
指令
@functions
指令允许将 C# 成员(字段、属性和方法)添加到生成的类中:
@functions {
// C# members (fields, properties, and methods)
}
//示例
@functions {
public string GetHello()
{
return "Hello";
}
}
<div>From method: @GetHello()</div>
//输出
<div>From method: Hello</div>
//生成的 Razor C# 类
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor;
public class _Views_Home_Test_cshtml : RazorPage<dynamic>
{
// Functions placed between here
public string GetHello()
{
return "Hello";
}
// And here.
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
WriteLiteral("\r\n<div>From method: ");
Write(GetHello());
WriteLiteral("</div>\r\n");
}
#pragma warning restore 1998
8.4@implements
指令
@implements
指令为生成的类实现接口。
@implements IDisposable
<h1>Example</h1>
@functions {
private bool _isDisposed;
...
public void Dispose() => _isDisposed = true;
}
8.5@inherits
指令
@inherits
指令对视图继承的类提供完全控制:
@inherits TypeNameOfClassToInheritFrom
//自定义Razor page类型
using Microsoft.AspNetCore.Mvc.Razor;
public abstract class CustomRazorPage<TModel> : RazorPage<TModel>
{
public string CustomText { get; } =
"Gardyloo! - A Scottish warning yelled from a window before dumping" +
"a slop bucket on the street below.";
}
@inherits CustomRazorPage<TModel>
<div>Custom text: @CustomText</div>
//输出
<div>
Custom text: Gardyloo! - A Scottish warning yelled from a window before dumping
a slop bucket on the street below.
</div>
@Model
和 @inherits
可在同一视图中使用。
@inherits CustomRazorPage<TModel>
<div>The Login Email: @Model.Email</div>
<div>Custom text: @CustomText</div>
//输出
<div>The Login Email: rick@contoso.com</div>
<div>
Custom text: Gardyloo! - A Scottish warning yelled from a window before dumping
a slop bucket on the street below.
</div>
8.6@inject
指令
@inject
指令允许 Razor Page将服务从服务容器注入到视图。
8.7@layout
指令
仅适用于Razor组件(.razor
)。
@layout
指令为具有 @page
指令的可路由 Razor
组件指定布局。 布局组件用于避免代码重复和不一致。
8.8@model
指令
适用于 MVC 视图和 Razor Pages (.cshtml
)。
@model
指令指定传递到视图的模型类型。
@model TypeNameOfModel
8.9@namespace
指令
- 设置生成的 Razor 页面、MVC 视图或 Razor 组件的类的命名空间。
- 在目录树、
_ViewImports.cshtml
(views or pages) 、_Imports.razor
(Razor components)中从最接近的导入文件设置pages、views
或components
类的根派生命名空间。
@namespace Your.Namespace.Here
- 每页导入
Pages/_ViewImports.cshtml
。 Pages/_ViewImports.cshtml
包含@namespace Hello.World
。- 每个页面都有
Hello.World
,作为其命名空间的根。
Page | Namespace |
---|---|
Pages/Index.cshtml | Hello.World |
Pages/MorePages/Page.cshtml | Hello.World.MorePages |
Pages/MorePages/EvenMorePages/Page.cshtml | Hello.World.MorePages.EvenMorePages |
8.10@page
指令
@page
指令具有不同的效果,具体取决于其所在文件的类型。 指令:
- 在
.cshtml
文件中表示该文件是 Razor 页面。 - 指定 Razor 组件应直接处理请求。
8.11@preservewhitespace
指令
仅适用于 Razor 组件 (.razor
)。
设置为 false
(默认值)时,如果出现以下情况,则会删除来自 Razor 组件 (.razor
) 的呈现标记中的空格:
- 元素中的前导或尾随空白。
RenderFragment
参数中的前导或尾随空白。 例如,传递到另一个组件的子内容。- 在 C# 代码块(例如
@if
和@foreach
)之前或之后。
8.12@section
指令
适用于 MVC 视图和 Razor Pages (.cshtml
)。
指令 @section
与 MVC 和 Razor Pages 布局结合使用,使视图或页面能够呈现 HTML 页面不同部分的内容。
8.13@using
指令
@using
指令用于向生成的视图添加 C# using
指令。
在 Razor 组件中,@using
还控制哪些组件在范围内。
@using System.IO
@{
var dir = Directory.GetCurrentDirectory();
}
<p>@dir</p>
9.指令属性
Razor 指令属性由隐式表达式表示,@
符号后有保留关键字。 指令属性通常会更改元素的分析方式或启用不同的功能。
9.1@attributes
属性
仅适用于 Razor 组件 (.razor
)。
@attributes
允许组件呈现未声明的属性。
9.2@bind
属性
仅适用于 Razor 组件 (.razor
)。
组件中的数据绑定通过 @bind
属性实现。
9.3@bind:culture
属性
仅适用于 Razor 组件 (.razor
)。
将 @bind:culture
属性与 @bind
属性一起使用以提供 System.Globalization.CultureInfo
用于分析和设置值的格式。
9.4@on{EVENT}
属性
仅适用于 Razor 组件 (.razor
)。
Razor 为组件提供事件处理功能。
9.5@on{EVENT}:preventDefault
属性
仅适用于 Razor 组件 (.razor
)。
禁止事件的默认操作。
9.6@on{EVENT}:stopPropagation
属性
仅适用于 Razor 组件 (.razor
)。
停止事件的事件传播。
9.7@key
属性
仅适用于 Razor 组件 (.razor)
。
@key
指令属性使组件diffing
算法保证基于键的值保留元素或组件。
9.8@ref
属性
仅适用于 Razor 组件 (.razor
)。
组件引用 (@ref
) 提供了一种引用组件实例的方法,以便可以向该实例发出命令。
9.9@typeparam
属性
仅适用于 Razor 组件 (.razor
)。
@typeparam
指令声明生成的组件类的泛型类型参数:
@typeparam TEntity
支持具有 where
类型约束的泛型类型:
@typeparam TEntity where TEntity : IEntity
10.模板化 Razor 委托
通过 Razor 模板,可使用以下格式定义 UI 代码片段:
@<tag>...</tag>
示例一:
public class Pet
{
public string Name { get; set; }
}
@{
Func<dynamic, object> petTemplate = @<p>You have a pet named <strong>@item.Name</strong>.</p>;
var pets = new List<Pet>
{
new Pet { Name = "Rin Tin Tin" },
new Pet { Name = "Mr. Bigglesworth" },
new Pet { Name = "K-9" }
};
}
@foreach (var pet in pets)
{
@petTemplate(pet)
}
//输出
<p>You have a pet named <strong>Rin Tin Tin</strong>.</p>
<p>You have a pet named <strong>Mr. Bigglesworth</strong>.</p>
<p>You have a pet named <strong>K-9</strong>.</p>
示例二:
@using Microsoft.AspNetCore.Html
@functions {
public static IHtmlContent Repeat(IEnumerable<dynamic> items, int times,
Func<dynamic, IHtmlContent> template)
{
var html = new HtmlContentBuilder();
foreach (var item in items)
{
for (var i = 0; i < times; i++)
{
html.AppendHtml(template(item));
}
}
return html;
}
}
<ul>
@Repeat(pets, 3, @<li>@item.Name</li>)
</ul>
//输出
<ul>
<li>Rin Tin Tin</li>
<li>Rin Tin Tin</li>
<li>Rin Tin Tin</li>
<li>Mr. Bigglesworth</li>
<li>Mr. Bigglesworth</li>
<li>Mr. Bigglesworth</li>
<li>K-9</li>
<li>K-9</li>
<li>K-9</li>
</ul>