Razor Page
ASP.NET Core支持多种框架,除了MVC,还有Razor Page。
Razor Page和MVC区别
MVC
- Model:数据
- View:Html、Razor、TagHelpers
- Controller:逻辑
Razor Page
- 数据
- Html、Razor、TagHelpers
- 逻辑
MVC的实现是把Model、View、Controller分开,有一定的好处,但是增加了复杂性。而对于一些相对简单的项目,Razor Page是把MVC的部分合并到一起。
Razor Page路由
目录 |
请求路径1 |
请求路径2 |
/Pages/Index.cshtml |
/ |
/Index |
/Pages/Department.cshtml |
/Department |
|
/Pages/Department/EmployeeList.cshtml |
/Department/EmployeeList |
|
/Pages/Department/Index.cshtml |
/Department |
/Department/Index |
注意:
- Razor Page的页面默认放在Pages目录下面。
- 如果文件名为Index.cshtml,可以省略Index,用斜杠代替。
创建项目
打开VS2019,创建新项目,选择ASP.NET Core Web 应用程序。项目名称为ThreePage,选择ASP.NET Core 3.0版本,然后选择空模板,点击创建。
把Three项目中的Models文件夹和Services文件夹复制到本项目的根目录下。
打开Startup.cs,在构造函数注入IConfiguration。
public class Startup { private readonly IConfiguration _configuration;
public Startup(IConfiguration configuration) { _configuration = configuration; } }
|
然后把Three项目中的ThreeOptions.cs复制到本项目的根目录下。
在Startup.cs的ConfigureServices方法中,进行依赖注入。注意有一点不同的是,MVC是AddControllersWithViews,而这里是AddRazorPages。
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddRazorPages();
services.AddSingleton<IDepartmentService, DepartmentService>(); services.AddSingleton<IEmployeeService, EmployeeService>(); } }
|
修改Startup.cs中的Configure方法,注意RazorPage的UseEndpoints需要修改MapRazorPages。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); }
|
建立Razor Page
部门页面
项目右键,新建Pages文件夹,用于存放页面。在Pages下新建Razor视图,命名为Index.cshtml。
@page @using Three.Models @using Three.Services
@inject IDepartmentService departmentService
<div class="row"> <div class="col-md-10 offset-md-2"> <table class="table"> <tr> <th>Name</th> <th>Location</th> <th>EmployeeCount</th> <th>操作</th> </tr> <tr> <th>@Html.DisplayFor(expression: x => x.Departments)</th> </tr> </table> </div> </div>
@functions {
public IEnumerable<Department> Departments { get; set; }
public async Task OnGetAsync() { Departments = await departmentService.GetAll(); }
}
|
注意:
- Razor Page页面最前面写上@page。
- 在@functions代码块中,可以写处理请求的C#代码。
- 处理GET请求的方法命名为OnGet,或者是OnGetAsync。可以是异步方法或同步方法。同理,处理POST请求的方法名称是OnPost或OnPostAsync。
- 通过 @Html.DisplayFor使用Departments属性。
运行项目,可以看到正常显示。
添加布局和样式
和Three项目类似,依次进行以下操作:
- 在Pages下新建Shared文件夹,添加布局页_Layout.cshtml。
- 使用Libman,安装Bootstrap。
- 添加bundleconfig.json,使用bundle合并。
- 通过Nuget安装BuildBundlerMinifier包。
- 复制Three项目的images文件夹。
- 添加_ViewStart.cshtml,指定母页面。
- 添加_ViewImports.cshtml,引入Tag Helper。
- Pages下添加展示模板,Pages/DisplayTemplates/Department.cshtml。
_ViewImports.cshtml文件的内容如下。
@using ThreePage @namespace ThreePage.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
Department.cshtml代码如下。
@model Three.Models.Department
<tr> <td>@Model.Name</td> <td>@Model.Location</td> <td>@Model.EmployeeCount</td>
<td> </td> </tr>
|
运行项目,可以看到和Three项目的效果差不多了。
添加部门
Pages右键,新建Department文件夹,在Department下新建Razor页面,命名为AddDepartment.cshtml。
可以看到,除了AddDepartment.cshtml,还多了.cs文件。这个类就是页面的类,相当于之前的/Pages/Index.cshtml中@function代码块的内容。
编辑AddDepartment.cshtml.cs文件。添加Department属性,使用BindProperty特性修饰,可以让页面使用的属性绑定到Department属性中。
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.Threading.Tasks; using Three.Services;
namespace ThreePage.Pages.Department { public class AddDepartmentModel : PageModel { private readonly IDepartmentService _departmentService;
[BindProperty] public Three.Models.Department Department { get; set; }
public AddDepartmentModel(IDepartmentService departmentService) { _departmentService = departmentService; }
public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } await _departmentService.Add(Department); return RedirectToPage("/Index"); } } }
|
编辑AddDepartment.cshtml的代码如下。
@page @model ThreePage.Pages.Department.AddDepartmentModel
<form asp-action="Add"> <div class="row form-group"> <div class="col-md-2 offset-md-2"> <label asp-for="Department.Name"></label> </div> <div class="col-md-6"> <input class="form-control" asp-for="Department.Name" /> </div> </div> <div class="row form-group"> <div class="col-md-2 offset-md-2"> <label asp-for="Department.Location"></label> </div> <div class="col-md-6"> <input class="form-control" asp-for="Department.Location" /> </div> </div> <div class="row form-group"> <div class="col-md-2 offset-md-2"> <label asp-for="Department.EmployeeCount"></label> </div> <div class="col-md-6"> <input class="form-control" asp-for="Department.EmployeeCount" /> </div> </div> <div class="row"> <div class="col-md-2 offset-md-2"> <button type="submit" class="btn btn-primary">Add</button> </div> </div> </form>
|
在/Pages/Index.cshtml中怎加代码。通过TagHelper中的asp-page属性指定路由。
@page @using Three.Services @inject IDepartmentService departmentService
<div class="row"> <div class="col-md-10 offset-md-2"> <table class="table"> <tr> <th>Name</th> <th>Location</th> <th>EmployeeCount</th> <th>操作</th> </tr> @Html.DisplayFor(expression: x => x.Departments) </table> </div> </div>
<div class="row"> <div class="col-md-4"> <a asp-page="Department/AddDepartment">Add</a> </div> </div>
@functions {
public IEnumerable<Three.Models.Department> Departments { get; set; }
public async Task OnGetAsync() { Departments = await departmentService.GetAll(); }
}
|
员工列表
Pages右键,新建Employee文件夹,在Employee下新建Razor视图,命名为EmployeeList.cshtml。@page的作用是获取departmentId参数并在C#代码中使用。
@page "{departmentId:int}"
@using Microsoft.AspNetCore.Mvc.RazorPages @using Three.Models @using Three.Services
@model EmployeeListModel
<div class="row"> <div class="col-md-10 offset-md-2"> <table class="table"> <tr> <th>First Name</th> <th>Last Name</th> <th>Gender</th> <th>Is Fired</th> <th>操作</th> </tr> @Html.DisplayFor(expression: x => x.Employees) </table> </div> </div>
@functions { public class EmployeeListModel : PageModel { private readonly IEmployeeService _employeeService;
public EmployeeListModel(IEmployeeService employeeService) { _employeeService = employeeService; }
public IEnumerable<Employee> Employees { get; set; }
public async Task OnGet(int departmentId) { Employees = await _employeeService.GetByDepartmentId(departmentId);
ViewData["DepartmentId"] = departmentId; } } }
|
添加员工列表模板。在DisplayTemplates下,添加Razor视图,命名为Employee.cshtml。
@model Three.Models.Employee
<tr> <td>@Model.FirstName</td> <td>@Model.LastName</td> <td>@Model.Gender</td> <td>@(Model.Fired ? "是" : "")</td>
<td> @if (!Model.Fired) { } </td> </tr>
|
然后在模板页面Department.cshtml下,增加Employees操作。
@model Three.Models.Department
<tr> <td>@Model.Name</td> <td>@Model.Location</td> <td>@Model.EmployeeCount</td>
<td> <a asp-page="Employee/EmployeeList" asp-route-departmentId="@Model.Id">Employees</a> </td> </tr>
|
添加员工
在员工列表页面EmployeeList.cshtml中,增加一个添加员工操作,跳转到添加员工页面。
<div class="row"> <div class="col-md-10 offset-md-2"> <table class="table"> <tr> <th>First Name</th> <th>Last Name</th> <th>Gender</th> <th>Is Fired</th> <th>操作</th> </tr> @Html.DisplayFor(expression: x => x.Employees) </table> <a asp-page="AddEmployee" asp-route-departmentId="@ViewData["DepartmentId"]">Add</a> </div> </div>
|
在Pages/Employee下新建添加员工页面Razor页面,命名为AddEmployee.cshtml。
AddEmployee.cshtml页面的代码如下。
@page "{departmentId:int}" @using Three.Models @model ThreePage.Pages.Employee.AddEmployeeModel
<form method="post">
<div class="row form-group"> <div class="col-md-2 offset-md-2"> <label asp-for="Employee.FirstName"></label> </div> <div class="col-md-6"> <input class="form-control" asp-for="Employee.FirstName" /> </div> </div> <div class="row form-group"> <div class="col-md-2 offset-md-2"> <label asp-for="Employee.LastName"></label> </div> <div class="col-md-6"> <input class="form-control" asp-for="Employee.LastName" /> </div> </div> <div class="row form-group"> <div class="col-md-2 offset-md-2"> <label asp-for="Employee.Gender"></label> </div> <div class="col-md-6"> <select class="form-control" asp-for="Employee.Gender" asp-items="Html.GetEnumSelectList<Gender>()"> </select> </div> </div> <div class="row"> <div class="col-md-2 offset-md-4"> <button type="submit" class="btn btn-primary">Add</button> </div> </div> </form>
|
AddEmployee.cshtml.cs的代码如下。
using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Three.Services;
namespace ThreePage.Pages.Employee { public class AddEmployeeModel : PageModel { private readonly IEmployeeService _employeeService;
public AddEmployeeModel(IEmployeeService employeeService) { _employeeService = employeeService; }
[BindProperty] public Three.Models.Employee Employee { get; set; }
public async Task<IActionResult> OnPostAsync(int departmentId) { Employee.DepartmentId = departmentId;
if (!ModelState.IsValid) { return Page(); }
await _employeeService.Add(Employee);
return RedirectToPage("EmployeeList", routeValues: new { departmentId }); } } }
|
解雇操作
在员工列表的模板页面Pages/DisplayTemplates/Employee.cshtml中,修改代码,增加解雇操作入口。
@model Three.Models.Employee
<tr> <td>@Model.FirstName</td> <td>@Model.LastName</td> <td>@Model.Gender</td> <td>@(Model.Fired ? "是" : "")</td>
<td> @if (!Model.Fired) { <a asp-page="EmployeeList" asp-page-handler="Fire" asp-route-employeeId="@Model.Id" asp-route-departmentId="@Model.DepartmentId"> Fire </a> } </td> </tr>
|
然后在EmployeeList.cshtml中,C#代码部分添加方法OnGetFireAsync,该方法接收两个参数。
public async Task<IActionResult> OnGetFireAsync(int employeeId, int departmentId) { await _employeeService.Fire(employeeId); return RedirectToPage("EmployeeList", routeValues: new { departmentId }); }
|
使用View Component
复制Three项目中的,Components文件夹,到本项目的Pages目录下。
复制Three项目中的,ViewComponents文件夹到本项目的根目录下,并修改CompanySummaryViewComponent.cs的命名空间为ThreePage。
using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Three.Services;
namespace ThreePage.ViewComponents { public class CompanySummaryViewComponent : ViewComponent { private readonly IDepartmentService _departmentService;
public CompanySummaryViewComponent(IDepartmentService departmentService) { _departmentService = departmentService; } public async Task<IViewComponentResult> InvokeAsync(string title) { ViewBag.Title = title; var summary = await _departmentService.GetCompanySummary(); return View(summary); } } }
|
在_ViewImports.cshtml中引入。
@using ThreePage @namespace ThreePage.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper "*, ThreePage"
|
在Pages/Index.cshtml中使用。
<div class="row"> <div class="col-md-4 offset-md-2"> <a asp-page="Department/AddDepartment">Add</a> </div> <div class="col-md-4"> @await Component.InvokeAsync(name: "CompanySummary", arguments: new { title = "部门列表页的汇总" }) <vc:company-summary title="部门列表页的汇总2"></vc:company-summary> </div> </div>
|
运行项目,View Component正常显示。