ASP.NET Core 3.x 入门(四)Razor Page

此入门教程是记录下方参考资料视频的学习过程
开发工具:Visual Studio 2019

参考资料:https://www.bilibili.com/video/BV1c441167KQ
API文档:https://docs.microsoft.com/zh-cn/dotnet/api/?view=aspnetcore-3.1

目录

ASP.NET Core 3.x 入门(一)创建项目 和 部署

ASP.NET Core 3.x 入门(二)建立 Controller ,使用 Tag Helper

ASP.NET Core 3.x 入门(三)View Component

ASP.NET Core 3.x 入门(四)Razor Page

ASP.NET Core 3.x 入门(五)SignalR

ASP.NET Core 3.x 入门(六)Blazor

ASP.NET Core 3.x 入门(七)Web API

ASP.NET Core 3.x 入门(八)gRPC - Protocol Buffer

ASP.NET Core 3.x 入门(九)gRPC in ASP.NET Core 3.x

基本概念

ASP .NET Core 支持多种编程模型

MVC:

  1. Model:数据
  2. View:Html、Razor、TagHelper
  3. Controller:逻辑

Razor Page:

  1. 数据
  2. Html、Razor、TagHelper
  3. 逻辑

使用 Razor Page 重新编写之前的 MVC 例子

Razor Page 路由

Razor Page 所有页面都在 Pages 目录下

  • /Pages/Index.cshtml
    若路径存在,则以下方式都可以访问

    • /
    • /Index
  • /Pages/Department.cshtml
    只需要去掉 cshtml 后缀名就可以访问

    • /Department
  • /Pages/Department/EmployeeList.cshtml
    若 Pages 目录下还有目录,就在访问路径上添加目录名称

    • /Department/EmployeeList
  • /Pages/Department/Index.cshtml
    若 Pages 目录下的目录也有 Index.cshtml ,以下方式都可以访问

    • /Department
    • /Department/Index

新建项目

  1. 还是 ASP.NET Core 项目,空模板
  2. 复制原先项目的 Models 和 Services 文件夹,到新建项目目录下,注意命名空间
  3. 修改 Startup.cs
private readonly IConfiguration _configuration;

public Startup(IConfiguration configuration)
{
    this._configuration = configuration;
}
  1. 也别忘记 Options.cs 和 appsettings.json
    My_RazorPage_ProgramOptions.cs
public class My_RazorPage_ProgramOptions
{
    public int BoldDepartmentEmployeeCountThreshold { get; set; }
}

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",



  "My_RazorPage_Program": {
    //部门人数大于 30 就加粗
    "BoldDepartmentEmployeeCountThreshold": 30
  }
}
  1. 修改 Start.cs 下的 ConfigureSercvices() 方法
public void ConfigureServices(IServiceCollection services)
{
    //注册 RazorPages 服务
    services.AddRazorPages();

    services.AddSingleton<IClock, ChinaClock>();
    services.AddSingleton<IDepartmentService, DepartmentService>();
    services.AddSingleton<IEmployeeService, EmployeeService>();

    services.Configure<My_RazorPage_ProgramOptions>(this._configuration.GetSection("My_RazorPage_Program"));
}
  1. 修改 Start.cs 下的 Configure() 方法
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseStaticFiles();

    app.UseHttpsRedirection();

    app.UseAuthentication();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
  1. 项目下新建 Pages 文件夹

  2. 添加静态文件,省略,详细见上文

  3. 为了使用 TagHelper 和 模板,在 Pages 目录下新建 _ViewImports.cshtml 和 _ViewStart.cshtml 文件,跟上面的项目是一样的
    _ViewImports.cshtml

@using My_RazorPage_Program
@namespace My_RazorPage_Program.Pages
@addTagHelper *,Microsoft.AspNetCore.Mvc.TagHelpers

_ViewStart.cshtml

@{
    Layout = "_Layout";
}

具体使用

Pages 目录下 Department、Employee、Shared、Pages/Department/DisplayTemplates 文件夹
Department 和 Employee 是具体页面,Shared 存放布局,DisplayTemplates 存放模板

Pages/Shared 目录下新建 _Layout.cshtml ,内容跟之前的一致

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @* 开发环境加载完整的css *@
    <environment include="Development">
        <link rel="stylesheet" asp-href-include="css/*" asp-href-exclude="css/all.min.css" />
    </environment>
    @* 其它环境 *@
    <environment exclude="Development">
        <link rel="stylesheet" asp-href-include="css/all.min.css" />
    </environment>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-2">
                @* asp-append-version="true",不缓存图片 *@
                <img asp-append-version="true" alt="Logo" src="~/images/logo.png" style="height:60px;" />
            </div>
            <div class="col-md-10">
                <span class="h2">@ViewBag.Title</span>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                @RenderBody()
            </div>
        </div>
    </div>
</body>
</html>

Pages/Department 目录下新建 Index.cshtml

@page
@using My_RazorPage_Program.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>Employee</th>
                <th>操作</th>
            </tr>
            @* 由于这个类是匿名的,所以 ReSharper 识别不出来,实际运行不会报错,VS 可以识别和智能提示 *@
            @* 这整个文件对应的类是 _Page_Pages_Index_cshtml ,也是 model ,这个 x 就是这个页面 *@
            @Html.DisplayFor(x => x.Departments)
        </table>
    </div>
</div>


@functions
{
    public IEnumerable<My_RazorPage_Program.Models.Department> Departments { get; set; }

    //OnGet() 处理 GET 请求,可以同步,也可以异步,POST 同理
    public async Task OnGetAsync()
    {
        this.Departments = await departmentService.GetAll();
    }
}

Pages/Department/DisplayTemplates 目录下新建 Department.cshtml
和之前的项目一致,可以直接复制,这里只写一些必要的

@model My_RazorPage_Program.Models.Department

<tr>
    <td>@Model.Name</td>
    <td>@Model.Location</td>
    <td>@Model.EmployeeCount</td>
</tr>

效果图

实现添加部门查看人员的功能

添加部门

Pages/Department 目录新建 Razor Page 空模板 ,命名 AddDepartment
创建后除了 cshtml 页面还有一个 cshtml.cs 文件,这就是这个页面的类,和上面直接在页面中写代码的效果是一样的,在 @model 中被指定
AddDepartment.cshtml.cs

public class AddDepartmentModel : PageModel
{
    [BindProperty]
    public My_RazorPage_Program.Models.Department Department { get; set; }

    private readonly IDepartmentService _departmentService;

    public AddDepartmentModel(IDepartmentService departmentService)
    {
        this._departmentService = departmentService;
    }

    public async Task<IActionResult> OnPostAsync()
    {
        await this._departmentService.Add(this.Department);

        //若在相同目录下,可以直接写页面名称
        return RedirectToPage("/Department/Index");
    }
}

[BindProperty]用于绑定属性,这样就可以在页面中访问属性,但是需要使用属性去引用
因为 Razor Page 可以使用 url 去访问对应页面,所以这个类的 OnGet() 方法没必要,使用 asp-page 去访问即可

AddDepartment.cshtml

@page
@model My_RazorPage_Program.Pages.Department.AddDepartmentModel

<form asp-action="Add">
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            @* asp-for 的作用是将 Model 中使用 [Display(Name = "XX)] 的属性,在 label 中显示为 XX *@
            <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-1-md-2">
            <button type="submit" class="btn btn-primary">Add</button>
        </div>
    </div>

</form>

Department/Index.cstml 页面下方添加

<div class="row">
    <div class="col-md-4">
        <a asp-page="AddDepartment">Add</a>
    </div>
</div>

查看人员

/Pages/Employee 目录下新建 Razor View ,命名 EmployeeList.cshtml

@page "{departmentId:int}"

@using Microsoft.AspNetCore.Mvc.RazorPages
@using My_RazorPage_Program.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(x => x.Employees)
        </table>
        <a asp-page="AddEmployee" asp-route-departmentId="@ViewData["DepartmentId"]">Add</a>
    </div>
</div>


@functions {
    public class EmployeeListModel : PageModel
    {
        private readonly IEmployeeService _employeeService;

        public EmployeeListModel(IEmployeeService employeeService)
        {
            this._employeeService = employeeService;
        }

        public IEnumerable<My_RazorPage_Program.Models.Employee> Employees { get; set; }

        public async Task OnGetAsync(int departmentId)
        {
            this.Employees = await this._employeeService.GetByDepartmentId(departmentId);

            ViewData["DepartmentId"] = departmentId;
        }

        //根据 Employee.cshtml 页面的 asp-action 和 GET、POST 命名
        public async Task<IActionResult> OnGetFireAsync(int employeeId, int departmentId)
        {
            await this._employeeService.Fire(employeeId);
            return RedirectToPage("EmployeeList", new { departmentId });
        }

    }
}

/Pages/Employee/DisplayTemplates 目录下新建 Razor View ,命名 Employee.cshtml

@model My_RazorPage_Program.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>

/Pages/Employee 目录下新建 Razor Page ,命名 AddEmployee.cshtml
AddEmployee.cshtml

@page "{departmentId:int}"
@using My_RazorPage_Program.Models
@model My_RazorPage_Program.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-1-md-2">
            <button type="submit" class="btn btn-primary">Add</button>
        </div>
    </div>

</form>

AddEmployee.cshtml.cs

public class AddEmployeeModel : PageModel
{
    private readonly IEmployeeService _employeeService;

    public AddEmployeeModel(IEmployeeService employeeService)
    {
        this._employeeService = employeeService;
    }

    [BindProperty]
    public My_RazorPage_Program.Models.Employee Employee { get; set; }

    public async Task<IActionResult> OnPostAsync(int departmentId)
    {
        this.Employee.DepartmentId = departmentId;

        await this._employeeService.Add(Employee);

        return RedirectToPage("EmployeeList", new { departmentId });
    }
}

到此为止,添加部门和查看人员就写完了,效果跟之前的 MVC 是一样的

View Component

项目目录下新建文件夹 ViewComponents
将上一个项目的 CompanySummary.cs 复制到 ViewComponents 目录下

Pages 目录下新建文件夹 Components
Pages/Components 目录下新建 CompanySummary
Pages/Components/CompanySummary 目录下新建 Razor View ,命名 Default.cshtml

@model My_RazorPage_Program.Models.CompanySummary

<div class="small">
    <div class="row h3">@ViewBag.Title</div>
    <div class="row">
        <div class="col-md-8">员工总数:</div>
        <div class="col-md-4">@Model.EmployeeCount</div>
    </div>
    <div class="row">
        <div class="col-md-8">部门平均人数:</div>
        <div class="col-md-4">@Model.AverageDepartmentEmployeeCount</div>
    </div>
</div>

其实直接复制上一个项目的就可以

Pages/Department/Index.cshtml 添加

<div class="col-md-4">
    @await Component.InvokeAsync("CompanySummary", new { title = "部门列表页的汇总" })
    <vc:company-summary title="部门列表页的汇总2"></vc:company-summary>
</div>

效果图

补充

asp-for="" 用于在 label 标签中显示 Model 中属性的 [Display(Name = "XX)] 的 XX
asp-page="" 用于跳转页面,就是正常的 Razor Page 调用,例如 asp-page="/Department/Index"
asp-route-参数名称="@变量" 用于跳转页面时传递参数,一般跟在 asp-page 的后面
asp-page-handler="方法名" 这个有点难说,在官方文档,或者看 EmployeeList.cshtml 中的注解
未提及的去看文档吧,我也不太懂

ASP.NET Core 3.x 入门(四)Razor page 结束

Razor Page 确实比 MVC 使用起来简单,Razor 页面之间的调用很直观
完整项目结构

posted @ 2021-05-13 20:06  .NET好耶  阅读(722)  评论(0编辑  收藏  举报