Razor 页面是 ASP.NET Core MVC 的一个新功能,它可以使基于页面的编码方式更简单高效。
若要查找使用模型视图控制器方法的教程,请参阅 ASP.NET Core MVC 入门 。
本文档介绍 Razor 页面。 它并不是分步教程。 如果认为某些部分过于复杂,请参阅 Razor 页面入门 。 有关 ASP.NET Core 的概述,请参阅 ASP.NET Core 简介 。
Install one of the following:
Visual Studio for Mac
在命令行中运行
dotnet new razor
。
在 Visual Studio for Mac 中打开生成的 .csproj 文件。
Visual Studio Code
在命令行中运行
dotnet new razor
。
.NET Core CLI
在命令行中运行
dotnet new razor
。
Razor 页面
Startup.cs 中已启用 Razor 页面:
public class Startup
public void ConfigureServices(IServiceCollection services)
// Includes support for Razor Pages and controllers.
services.AddMvc();
public void Configure(IApplicationBuilder app)
app.UseMvc();
请考虑一个基本页面:
@page
<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>
上述代码看上去类似于一个 Razor 视图文件。 不同之处在于 @page
指令。 @page
使文件转换为一个 MVC 操作 ,这意味着它将直接处理请求,而无需通过控制器处理。 @page
必须是页面上的第一个 Razor 指令。 @page
将影响其他 Razor 构造的行为。
将在以下两个文件中显示使用 PageModel
类的类似页面。 Pages/Index2.cshtml 文件:
@page
@using RazorPagesIntro.Pages
@model IndexModel2
<h2>Separate page model</h2>
@Model.Message
Pages/Index2.cshtml.cs 页面模型:
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
namespace RazorPagesIntro.Pages
public class IndexModel2 : PageModel
public string Message { get; private set; } = "PageModel in C#";
public void OnGet()
Message += $" Server time is { DateTime.Now }";
按照惯例,PageModel
类文件的名称与追加 .cs 的 Razor 页面文件名称相同。 例如,前面的 Razor 页面的名称为 Pages/Index2.cshtml。 包含 PageModel
类的文件的名称为 Pages/Index2.cshtml.cs。
页面的 URL 路径的关联由页面在文件系统中的位置决定。 下表显示了 Razor 页面路径及匹配的 URL:
文件名和路径
匹配的 URL
编写基本窗体
Razor 页面功能旨在简化 Web 浏览器常用的模式。 模型绑定、标记帮助程序和 HTML 帮助程序均只可用于 Razor 页面类中定义的属性。 请参考为 Contact
模型实现基本的“联系我们”窗体的页面:
在本文档中的示例中,DbContext
在 Startup.cs 文件中进行初始化。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesContacts.Data;
namespace RazorPagesContacts
public class Startup
public IHostingEnvironment HostingEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("name"));
services.AddMvc();
public void Configure(IApplicationBuilder app)
app.UseMvc();
数据模型:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Data
public class Customer
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; }
数据库上下文:
using Microsoft.EntityFrameworkCore;
namespace RazorPagesContacts.Data
public class AppDbContext : DbContext
public AppDbContext(DbContextOptions options)
: base(options)
public DbSet<Customer> Customers { get; set; }
Pages/Create.cshtml 视图文件:
@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Enter your name.
<div asp-validation-summary="All"></div>
<form method="POST">
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" />
</form>
</body>
</html>
Pages/Create.cshtml.cs 页面模型:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
namespace RazorPagesContacts.Pages
public class CreateModel : PageModel
private readonly AppDbContext _db;
public CreateModel(AppDbContext db)
_db = db;
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
按照惯例,PageModel
类命名为 <PageName>Model
并且它与页面位于同一个命名空间中。
使用 PageModel
类,可以将页面的逻辑与其展示分离开来。 它定义了页面处理程序,用于处理发送到页面的请求和用于呈现页面的数据。 借助这种分离,可以通过依赖关系注入管理页面依赖关系,并对页面执行单元测试。
页面包含 OnPostAsync
处理程序方法,它在 POST
请求上运行(当用户发布窗体时)。 可以为任何 HTTP 谓词添加处理程序方法。 最常见的处理程序是:
OnGet
,用于初始化页面所需的状态。 OnGet 示例。
public class Startup
public void ConfigureServices(IServiceCollection services)
// Includes support for Razor Pages and controllers.
services.AddMvc();
public void Configure(IApplicationBuilder app)
app.UseMvc();
请考虑一个基本页面:
@page
<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>
上述代码看上去类似于一个 Razor 视图文件。 不同之处在于 @page
指令。 @page
使文件转换为一个 MVC 操作 ,这意味着它将直接处理请求,而无需通过控制器处理。 @page
必须是页面上的第一个 Razor 指令。 @page
将影响其他 Razor 构造的行为。
将在以下两个文件中显示使用 PageModel
类的类似页面。 Pages/Index2.cshtml 文件:
@page
@using RazorPagesIntro.Pages
@model IndexModel2
<h2>Separate page model</h2>
@Model.Message
Pages/Index2.cshtml.cs 页面模型:
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
namespace RazorPagesIntro.Pages
public class IndexModel2 : PageModel
public string Message { get; private set; } = "PageModel in C#";
public void OnGet()
Message += $" Server time is { DateTime.Now }";
按照惯例,PageModel
类文件的名称与追加 .cs 的 Razor 页面文件名称相同。 例如,前面的 Razor 页面的名称为 Pages/Index2.cshtml。 包含 PageModel
类的文件的名称为 Pages/Index2.cshtml.cs。
页面的 URL 路径的关联由页面在文件系统中的位置决定。 下表显示了 Razor 页面路径及匹配的 URL:
文件名和路径
匹配的 URL
编写基本窗体
Razor 页面功能旨在简化 Web 浏览器常用的模式。 模型绑定、标记帮助程序和 HTML 帮助程序均只可用于 Razor 页面类中定义的属性。 请参考为 Contact
模型实现基本的“联系我们”窗体的页面:
在本文档中的示例中,DbContext
在 Startup.cs 文件中进行初始化。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesContacts.Data;
namespace RazorPagesContacts
public class Startup
public IHostingEnvironment HostingEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("name"));
services.AddMvc();
public void Configure(IApplicationBuilder app)
app.UseMvc();
数据模型:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Data
public class Customer
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; }
数据库上下文:
using Microsoft.EntityFrameworkCore;
namespace RazorPagesContacts.Data
public class AppDbContext : DbContext
public AppDbContext(DbContextOptions options)
: base(options)
public DbSet<Customer> Customers { get; set; }
Pages/Create.cshtml 视图文件:
@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Enter your name.
<div asp-validation-summary="All"></div>
<form method="POST">
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" />
</form>
</body>
</html>
Pages/Create.cshtml.cs 页面模型:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
namespace RazorPagesContacts.Pages
public class CreateModel : PageModel
private readonly AppDbContext _db;
public CreateModel(AppDbContext db)
_db = db;
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
按照惯例,PageModel
类命名为 <PageName>Model
并且它与页面位于同一个命名空间中。
使用 PageModel
类,可以将页面的逻辑与其展示分离开来。 它定义了页面处理程序,用于处理发送到页面的请求和用于呈现页面的数据。 借助这种分离,可以通过依赖关系注入管理页面依赖关系,并对页面执行单元测试。
页面包含 OnPostAsync
处理程序方法,它在 POST
请求上运行(当用户发布窗体时)。 可以为任何 HTTP 谓词添加处理程序方法。 最常见的处理程序是:
OnGet
,用于初始化页面所需的状态。 OnGet 示例。
OnPost
,用于处理窗体提交。
Async
命名后缀为可选,但是按照惯例通常会将它用于异步函数。 前面示例中的
OnPostAsync
代码看上去与通常在控制器中编写的内容相似。 前面的代码通常用于 Razor 页面。 多数 MVC 基元(例如
模型绑定
、
验证
和操作结果)都是共享的。
之前的
OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
OnPostAsync
的基本流:
检查验证错误。
如果没有错误,则保存数据并重定向。
如果有错误,则再次显示页面并附带验证消息。 客户端验证与传统的 ASP.NET Core MVC 应用程序相同。 很多情况下,都会在客户端上检测到验证错误,并且从不将它们提交到服务器。
成功输入数据后,OnPostAsync
处理程序方法调用 RedirectToPage
帮助程序方法来返回 RedirectToPageResult
的实例。 RedirectToPage
是新的操作结果,类似于 RedirectToAction
或 RedirectToRoute
,但是已针对页面进行自定义。 在前面的示例中,它将重定向到根索引页 (/Index
)。 页面 URL 生成部分中详细介绍了 RedirectToPage
。
提交的窗体存在(已传递到服务器的)验证错误时,OnPostAsync
处理程序方法调用 Page
帮助程序方法。Page
返回 PageResult
的实例。 返回 Page
的过程与控制器中的操作返回 View
的过程相似。PageResult
是处理程序方法的默认 返回类型。 返回 void
的处理程序方法将显示页面。
Customer
属性使用 [BindProperty]
特性来选择加入模型绑定。
public class CreateModel : PageModel
private readonly AppDbContext _db;
public CreateModel(AppDbContext db)
_db = db;
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
默认情况下,Razor 页面只绑定带有非 GET 谓词的属性。 绑定属性可以减少需要编写的代码量。 绑定通过使用相同的属性显示窗体字段 (<input asp-for="Customer.Name" />
) 来减少代码,并接受输入。
出于安全原因,必须选择绑定 GET 请求数据以对模型属性进行分页。 请在将用户输入映射到属性前对其进行验证。 当构建依赖查询字符串或路由值的功能时,选择加入此行为非常有用。
若要将属性绑定在 GET 请求上,请将 [BindProperty]
特性的 SupportsGet
属性设置为 true
:[BindProperty(SupportsGet = true)]
主页 (Index.cshtml):
@page
@model RazorPagesContacts.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<h1>Contacts</h1>
<form method="post">
<table class="table">
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
@foreach (var contact in Model.Customers)
<td>@contact.Id</td>
<td>@contact.Name</td>
<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>
<button type="submit" asp-page-handler="delete"
asp-route-id="@contact.Id">delete</button>
</tbody>
</table>
<a asp-page="./Create">Create</a>
</form>
Index.cshtml.cs 隐藏文件:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace RazorPagesContacts.Pages
public class IndexModel : PageModel
private readonly AppDbContext _db;
public IndexModel(AppDbContext db)
_db = db;
public IList<Customer> Customers { get; private set; }
public async Task OnGetAsync()
Customers = await _db.Customers.AsNoTracking().ToListAsync();
public async Task<IActionResult> OnPostDeleteAsync(int id)
var contact = await _db.Customers.FindAsync(id);
if (contact != null)
_db.Customers.Remove(contact);
await _db.SaveChangesAsync();
return RedirectToPage();
Index.cshtml 文件包含以下标记来创建每个联系人项的编辑链接:
<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>
定位点标记帮助程序 使用 asp-route-{value}
属性生成“编辑”页面的链接。 此链接包含路由数据及联系人 ID 。 例如 http://localhost:5000/Edit/1
。
Pages/Edit.cshtml 文件:
@page "{id:int}"
@model RazorPagesContacts.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
ViewData["Title"] = "Edit Customer";
<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
<div asp-validation-summary="All"></div>
<input asp-for="Customer.Id" type="hidden" />
<label asp-for="Customer.Name"></label>
<input asp-for="Customer.Name" />
<span asp-validation-for="Customer.Name" ></span>
<button type="submit">Save</button>
</form>
第一行包含 @page "{id:int}"
指令。 路由约束 "{id:int}"
告诉页面接受包含 int
路由数据的页面请求。 如果页面请求未包含可转换为 int
的路由数据,则运行时返回 HTTP 404(未找到)错误。 若要使 ID 可选,请将 ?
追加到路由约束:
@page "{id:int?}"
Pages/Edit.cshtml.cs 文件:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
namespace RazorPagesContacts.Pages
public class EditModel : PageModel
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
_db = db;
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
Customer = await _db.Customers.FindAsync(id);
if (Customer == null)
return RedirectToPage("/Index");
return Page();
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Attach(Customer).State = EntityState.Modified;
await _db.SaveChangesAsync();
catch (DbUpdateConcurrencyException)
throw new Exception($"Customer {Customer.Id} not found!");
return RedirectToPage("/Index");
Index.cshtml 文件还包含用于为每个客户联系人创建删除按钮的标记:
<button type="submit" asp-page-handler="delete"
asp-route-id="@contact.Id">delete</button>
删除按钮采用 HTML 呈现,其 formaction
包括参数:
asp-route-id
属性指定的客户联系人 ID。
asp-page-handler
属性指定的 handler
。
下面是呈现的删除按钮的示例,其中客户联系人 ID 为 1
:
<button type="submit" formaction="/?id=1&handler=delete">delete</button>
选中按钮时,向服务器发送窗体 POST
请求。 按照惯例,根据方案 OnPost[handler]Async
基于 handler
参数的值来选择处理程序方法的名称。
因为本示例中 handler
是 delete
,因此 OnPostDeleteAsync
处理程序方法用于处理 POST
请求。 如果 asp-page-handler
设置为不同值(如 remove
),则选择名称为 OnPostRemoveAsync
的页面处理程序方法。
public async Task<IActionResult> OnPostDeleteAsync(int id)
var contact = await _db.Customers.FindAsync(id);
if (contact != null)
_db.Customers.Remove(contact);
await _db.SaveChangesAsync();
return RedirectToPage();
OnPostDeleteAsync
方法:
接受来自查询字符串的 id
。
使用 FindAsync
查询客户联系人的数据库。
如果找到客户联系人,则从客户联系人列表将其删除。 数据库将更新。
调用 RedirectToPage
,重定向到根索引页 (/Index
) 。
XSRF/CSRF 和 Razor 页面
无需为防伪验证编写任何代码。Razor 页面自动将防伪标记生成过程和验证过程包含在内。
将布局、分区、模板和标记帮助程序用于 Razor 页面
页面可使用 Razor 视图引擎的所有功能。 布局、分区、模板、标记帮助程序、 _ViewStart.cshtml 和 _ViewImports.cshtml 的工作方式与它们在传统的 Razor 视图中的工作方式相同。
我们来使用其中的一些功能来整理此页面。
向 Pages/_Layout.cshtml 添加布局页面:
<!DOCTYPE html>
<title>Razor Pages Sample</title>
</head>
<a asp-page="/Index">Home</a>
@RenderBody()
<a asp-page="/Customers/Create">Create</a> <br />
</body>
</html>
控制每个页面的布局(页面选择退出布局时除外)。
导入 HTML 结构,例如 JavaScript 和样式表。
请参阅布局页面了解详细信息。
在 Pages/_ViewStart.cshtml 中设置 Layout 属性:
Layout = "_Layout";
注意:布局位于“页面”文件夹中。 页面按层次结构从当前页面的文件夹开始查找其他视图(布局、模板、分区)。 可以从“页面”文件夹下的任意 Razor 页面使用“页面”文件夹中的布局。
建议不要将布局文件放在“视图/共享”文件夹中。 视图/共享 是一种 MVC 视图模式。Razor 页面旨在依赖文件夹层次结构,而非路径约定。
Razor 页面中的视图搜索包含“页面”文件夹。 用于 MVC 控制器和传统 Razor 视图的布局、模板和分区可直接工作。
添加 Pages/_ViewImports.cshtml 文件:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
本教程的后续部分中将介绍 @namespace
。 @addTagHelper
指令将内置标记帮助程序引入“页面”文件夹中的所有页面。
页面上显式使用 @namespace
指令后:
@page
@namespace RazorPagesIntro.Pages.Customers
@model NameSpaceModel
<h2>Name space</h2>
@Model.Message
此指令将为页面设置命名空间。 @model
指令无需包含命名空间。
_ViewImports.cshtml 中包含 @namespace
指令后,指定的命名空间将为在导入 @namespace
指令的页面中生成的命名空间提供前缀。 生成的命名空间的剩余部分(后缀部分)是包含 _ViewImports.cshtml 的文件夹与包含页面的文件夹之间以点分隔的相对路径。
例如,代码隐藏文件 Pages/Customers/Edit.cshtml.cs 显式设置命名空间:
namespace RazorPagesContacts.Pages
public class EditModel : PageModel
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
_db = db;
// Code removed for brevity.
Pages/_ViewImports.cshtml 文件设置以下命名空间:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
为 Pages/Customers/Edit.cshtml Razor 页面生成的命名空间与代码隐藏文件相同. 已对 @namespace
指令进行设计,因此添加到项目的 C# 类和页面生成的代码可直接工作,而无需添加代码隐藏文件的 @using
指令。
注意: @namespace
也可用于传统的 Razor 视图。
原始的 Pages/Create.cshtml 视图文件:
@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Enter your name.
<div asp-validation-summary="All"></div>
<form method="POST">
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" />
</form>
</body>
</html>
更新后的 Pages/Create.cshtml 视图文件:
@page
@model CreateModel
Enter your name.
<div asp-validation-summary="All"></div>
<form method="POST">
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" />
</form>
</body>
</html>
页面的 URL 生成
之前显示的 Create
页面使用 RedirectToPage
:
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
应用具有以下文件/文件夹结构:
/Pages
Index.cshtml
/Customer
Create.cshtml
Edit.cshtml
Index.cshtml
成功后, Pages/Customers/Create.cshtml 和 Pages/Customers/Edit.cshtml 页面将重定向到 Pages/Index.cshtml 。字符串 /Index
是用于访问上一页的 URI 的组成部分。可以使用字符串 /Index
生成 Pages/Index.cshtml 页面的 URI 。例如:
Url.Page("/Index", ...)
<a asp-page="/Index">My Index Page</a>
RedirectToPage("/Index")
页面名称是从根“/Pages”文件夹到页面的路径(包含前导 /
,例如 /Index
)。相较于仅对 URL 硬编码,前面的 URL 生成示例的功能更加强大。URL 生成使用路由,并且可以根据目标路径定义路由的方式生成参数并对参数编码。
页面的URL生成支持相对名称。 下表显示了 Pages/Customers/Create.cshtml 中不同的 RedirectToPage
参数选择的索引页:
RedirectToPage(x)
RedirectToPage("Index")
、 RedirectToPage("./Index")
和 RedirectToPage("../Index")
是相对名称。 结合 RedirectToPage
参数与当前页的路径来计算目标页面的名称。
构建结构复杂的站点时,相对名称链接很有用。 如果使用相对名称链接文件夹中的页面,则可以重命名该文件夹。 所有链接仍然有效(因为这些链接未包含此文件夹名称)。
TempData
ASP.NET在控制器上公开了 TempData 属性。 此属性存储未读取的数据。 Keep
和 Peek
方法可用于检查数据,而不执行删除。 多个请求需要数据时, TempData
有助于进行重定向。
[TempData]
是 ASP.NET Core 2.0 中的新属性,在控制器和页面上受支持。
下面的代码使用 TempData
设置 Message
的值:
public class CreateDotModel : PageModel
private readonly AppDbContext _db;
public CreateDotModel(AppDbContext db)
_db = db;
[TempData]
public string Message { get; set; }
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
Message = $"Customer {Customer.Name} added";
return RedirectToPage("./Index");
Pages/Customers/Index.cshtml 文件中的以下标记使用 TempData
显示 Message
的值。
<h3>Msg: @Model.Message</h3>
Pages/Customers/Index.cshtml.cs页面模型将[TempData]
属性应用到Message
属性。
[TempData]
public string Message { get; set; }
请参阅 TempData 了解详细信息。
针对一个页面的多个处理程序
以下页面使用 asp-page-handler
标记帮助程序为两个页面处理程序生成标记:
@page
@model CreateFATHModel
Enter your name.
<div asp-validation-summary="All"></div>
<form method="POST">
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
</form>
</body>
</html>
前面示例中的窗体包含两个提交按钮,每个提交按钮均使用 FormActionTagHelper
提交到不同的 URL 。 asp-page-handler
是 asp-page
的配套属性。 asp-page-handler
生成提交到页面定义的各个处理程序方法的 URL 。未指定 asp-page
,因为示例已链接到当前页面。
页面模型:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
namespace RazorPagesContacts.Pages.Customers
public class CreateFATHModel : PageModel
private readonly AppDbContext _db;
public CreateFATHModel(AppDbContext db)
_db = db;
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnPostJoinListAsync()
if (!ModelState.IsValid)
return Page();
_db.Customers.Add(Customer);
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
public async Task<IActionResult> OnPostJoinListUCAsync()
if (!ModelState.IsValid)
return Page();
Customer.Name = Customer.Name?.ToUpper();
return await OnPostJoinListAsync();
前面的代码使用已命名处理程序方法。已命名处理程序方法通过采用名称中 On<HTTP Verb>
之后及 Async
之前的文本(如果有)创建。 在前面的示例中,页面方法是 OnPostJoinListAsync 和 OnPostJoinListUCAsync 。删除 OnPost 和 Async 后,处理程序名称为 JoinList
和 JoinListUC
。
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
使用前面的代码时,提交到 OnPostJoinListAsync
的 URL 路径为 http://localhost:5000/Customers/CreateFATH?handler=JoinList
。提交到 OnPostJoinListUCAsync
的 URL 路径为 http://localhost:5000/Customers/CreateFATH?handler=JoinListUC
。
自定义路由
如果你不喜欢 URL 中的查询字符串 ?handler=JoinList
,可以更改路由,将处理程序名称放在 URL 的路径部分。可以通过在 @page
指令后面添加使用双引号括起来的路由模板来自定义路由。
@page "{handler?}"
@model CreateRouteModel
Enter your name.
<div asp-validation-summary="All"></div>
<form method="POST">
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
</form>
</body>
</html>
前面的路由将处理程序放在了 URL 路径中,而不是查询字符串中。handler
前面的 ?
表示路由参数为可选。
可以使用 @page
将其他段和参数添加到页面的路由中。 其中的任何内容均会被追加到页面的默认路由中。 不支持使用绝对路径或虚拟路径更改页面的路由(如 "~/Some/Other/Path"
)。
配置和设置
若要配置高级选项,请在 MVC 生成器上使用 AddRazorPagesOptions
扩展方法:
public void ConfigureServices(IServiceCollection services)
services.AddMvc()
.AddRazorPagesOptions(options =>
options.RootDirectory = "/MyPages";
options.Conventions.AuthorizeFolder("/MyPages/Admin");
目前,可以使用 RazorPagesOptions
设置页面的根目录,或者为页面添加应用程序模型约定。 通过这种方式,我们在将来会实现更多扩展功能。
请参阅 Razor 页面入门,这篇文章以本文为基础编写。
指定 Razor 页面位于内容根目录中
默认情况下,Razor 页面位于 /Pages 目录的根位置。向 AddMvc 添加 WithRazorPagesAtContentRoot,以指定 Razor 页面位于应用的内容根目录 (ContentRootPath) 中:
services.AddMvc()
.AddRazorPagesOptions(options =>
.WithRazorPagesAtContentRoot();
指定 Razor 页面位于自定义根目录中
向 AddMvc 添加 WithRazorPagesRoot,以指定 Razor 页面位于应用中自定义根目录位置(提供相对路径):
services.AddMvc()
.AddRazorPagesOptions(options =>
.WithRazorPagesRoot("/path/to/razor/pages");
ASP.NET Core 简介