【转】asp.net Core 系列【一】——创建Web应用

ASP.NET Core 中的 Razor 页面介绍

Razor 页面是 ASP.NET Core MVC 的一个新功能,它可以使基于页面的编码方式更简单高效。

若要查找使用模型视图控制器方法的教程,请参阅 ASP.NET Core MVC 入门。

 

ASP.NET Core 2.0 必备组件

安装 .NET Core 2.0.0 或更高版本。

如果在使用 Visual Studio,请使用以下工作负载安装 Visual Studio 2017 版本 15.3 或更高版本:

  • ASP.NET 和 Web 开发
  • .NET Core 跨平台开发

 

创建 Razor 页面项目

  • Visual Studio  
  • Visual Studio for Mac  
  • Visual Studio Code  
  • .NET Core CLI

请参阅 Razor 页面入门,获取关于如何使用 Visual Studio 创建 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 RazorPages
@model IndexModel2<h2>Separate page model</h2>
<p>@Model.Message
</p>

 

Pages/Index2.cshtml.cs“代码隐藏”文件:

using Microsoft.AspNetCore.Mvc.RazorPages;
using System;namespace RazorPages
{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
/Pages/Index.cshtml/ 或 /Index
/Pages/Contact.cshtml/Contact
/Pages/Store/Contact.cshtml/Store/Contact
/Pages/Store/Index.cshtml/Store 或 /Store/Index

注意:

  • 默认情况下,运行时在“页面”文件夹中查找 Razor 页面文件。
  • URL 未包含页面时,Index 为默认页面。

编写基本窗体

Razor 页面功能旨在简化 Web 浏览器常用的模式。 模型绑定、标记帮助程序和 HTML 帮助程序均只可用于 Razor 页面类中定义的属性。 请参考为 Contact 模型实现基本的“联系我们”窗体的页面:

在本文档中的示例中,DbContext 在 Startup.cs 文件中进行初始化。

C#复制
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(); } } } 

数据模型:

C#复制
using System.ComponentModel.DataAnnotations;namespace RazorPagesContacts.Data
{public class Customer { public int Id { get; set; } [Required, StringLength(100)] public string Name { get; set; } } } 

数据库上下文:

C#复制
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 视图文件:

cshtml复制
@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<html>
<body><p>Enter your name.</p><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 代码隐藏视图文件:

C#复制
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 代码隐藏文件支持单元测试,但是需要你编写显式构造函数和类。 未使用 PageModel 代码隐藏文件的页面支持运行时编译,这在开发过程中可以作为一种优势。

页面包含 OnPostAsync 处理程序方法,它在 POST 请求上运行(当用户发布窗体时)。 可以为任何 HTTP 谓词添加处理程序方法。 最常见的处理程序是:

  • OnGet,用于初始化页面所需的状态。 OnGet 示例。
  • OnPost,用于处理窗体提交。

Async 命名后缀为可选,但是按照惯例通常会将它用于异步函数。 前面示例中的 OnPostAsync 代码看上去与通常在控制器中编写的内容相似。 前面的代码通常用于 Razor 页面。 多数 MVC 基元(例如模型绑定、验证和操作结果)都是共享的。

之前的 OnPostAsync 方法:

C#复制
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] 特性来选择加入模型绑定。

C#复制
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" />) 来减少代码,并接受输入。

主页 (Index.cshtml):

cshtml复制
@page
@model RazorPagesContacts.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<h1>Contacts</h1>
<form method="post"> <table class="table"> <thead> <tr> <th>ID</th> <th>Name</th> </tr> </thead> <tbody> @foreach (var contact in Model.Customers) { <tr> <td>@contact.Id</td> <td>@contact.Name</td> <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> </td> </tr> } </tbody> </table> <a asp-page="./Create">Create</a> </form> 

Index.cshtml.cs 隐藏文件:

C#复制
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 文件包含以下标记来创建每个联系人项的编辑链接:

cshtml复制
<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>

定位点标记帮助程序 使用 asp-route-{value} 属性生成“编辑”页面的链接。 此链接包含路由数据及联系人 ID。 例如 http://localhost:5000/Edit/1

Pages/Edit.cshtml 文件:

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" /> <div> <label asp-for="Customer.Name"></label> <div> <input asp-for="Customer.Name" /> <span asp-validation-for="Customer.Name" ></span> </div> </div> <div> <button type="submit">Save</button> </div> </form> 

第一行包含 @page "{id:int}" 指令。 路由约束 "{id:int}" 告诉页面接受包含 int 路由数据的页面请求。 如果页面请求未包含可转换为 int的路由数据,则运行时返回 HTTP 404(未找到)错误。

Pages/Edit.cshtml.cs 文件:

C#复制
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; try { await _db.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { throw new Exception($"Customer {Customer.Id} not found!"); } return RedirectToPage("/Index"); } } } 

Index.cshtml 文件还包含用于为每个客户联系人创建删除按钮的标记:

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

html复制
<button type="submit" formaction="/?id=1&amp;handler=delete">delete</button> 

选中按钮时,向服务器发送窗体 POST 请求。 按照惯例,根据方案 OnPost[handler]Async 基于 handler 参数的值来选择处理程序方法的名称。

因为本示例中 handler 是 delete,因此 OnPostDeleteAsync 处理程序方法用于处理 POST 请求。 如果 asp-page-handler 设置为不同值(如 remove),则选择名称为 OnPostRemoveAsync 的页面处理程序方法。

C#复制
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 添加布局页面:

cshtml复制
<!DOCTYPE html>
<html>
<head> <title>Razor Pages Sample</title> </head> <body> <a asp-page="/Index">Home</a> @RenderBody() <a asp-page="/Customers/Create">Create</a> <br /> </body> </html> 

布局:

  • 控制每个页面的布局(页面选择退出布局时除外)。
  • 导入 HTML 结构,例如 JavaScript 和样式表。

请参阅布局页面了解详细信息。

在 Pages/_ViewStart.cshtml 中设置 Layout 属性:

cshtml复制
@{Layout = "_Layout";
}

注意:布局位于“页面”文件夹中。 页面按层次结构从当前页面的文件夹开始查找其他视图(布局、模板、分区)。 可以从“页面”文件夹下的任意 Razor 页面使用“页面”文件夹中的布局。

建议不要将布局文件放在“视图/共享”文件夹中。 视图/共享 是一种 MVC 视图模式。 Razor 页面旨在依赖文件夹层次结构,而非路径约定。

Razor 页面中的视图搜索包含“页面”文件夹。 用于 MVC 控制器和传统 Razor 视图的布局、模板和分区可直接工作。

添加 Pages/_ViewImports.cshtml 文件:

cshtml复制
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

本教程的后续部分中将介绍 @namespace。 @addTagHelper 指令将内置标记帮助程序引入“页面”文件夹中的所有页面。

页面上显式使用 @namespace 指令后:

cshtml复制
@page
@namespace RazorPagesIntro.Pages.Customers@model NameSpaceModel<h2>Name space</h2>
<p>@Model.Message </p> 

此指令将为页面设置命名空间。 @model 指令无需包含命名空间。

_ViewImports.cshtml 中包含 @namespace 指令后,指定的命名空间将为在导入 @namespace 指令的页面中生成的命名空间提供前缀。 生成的命名空间的剩余部分(后缀部分)是包含 _ViewImports.cshtml 的文件夹与包含页面的文件夹之间以点分隔的相对路径。

例如,代码隐藏文件 Pages/Customers/Edit.cshtml.cs 显式设置命名空间:

C#复制
namespace RazorPagesContacts.Pages
{public class EditModel : PageModel { private readonly AppDbContext _db; public EditModel(AppDbContext db) { _db = db; } // Code removed for brevity. 

Pages/_ViewImports.cshtml 文件设置以下命名空间:

cshtml复制
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

为 Pages/Customers/Edit.cshtml Razor 页面生成的命名空间与代码隐藏文件相同. 已对 @namespace 指令进行设计,因此添加到项目的 C# 类和页面生成的代码可直接工作,而无需添加代码隐藏文件的 @using 指令。

注意:@namespace 也可用于传统的 Razor 视图。

原始的 Pages/Create.cshtml 视图文件:

cshtml复制
@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<html>
<body><p>Enter your name.</p><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 视图文件:

cshtml复制
@page
@model CreateModel<html>
<body> <p> Enter your name. </p> <div asp-validation-summary="All"></div> <form method="POST"> <div>Name: <input asp-for="Customer.Name" /></div> <input type="submit" /> </form> </body> </html> 

Razor 页面初学者项目包含 Pages/_ValidationScriptsPartial.cshtml,它与客户端验证联合。

页面的 URL 生成

之前显示的 Create 页面使用 RedirectToPage

C#复制
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")Pages/Index
RedirectToPage("./Index");Pages/Customers/Index
RedirectToPage("../Index")Pages/Index
RedirectToPage("Index")Pages/Customers/Index

RedirectToPage("Index")RedirectToPage("./Index") 和 RedirectToPage("../Index") 是相对名称。 结合 RedirectToPage 参数与当前页的路径来计算目标页面的名称。

构建结构复杂的站点时,相对名称链接很有用。 如果使用相对名称链接文件夹中的页面,则可以重命名该文件夹。 所有链接仍然有效(因为这些链接未包含此文件夹名称)。

TempData

ASP.NET 在控制器上公开了 TempData 属性。 此属性可存储数据,直至数据被读取。 Keep 和 Peek 方法可用于检查数据,而不执行删除。 多个请求需要数据时,TempData 有助于进行重定向。

[TempData] 是 ASP.NET Core 2.0 中的新属性,在控制器和页面上受支持。

下面的代码使用 TempData 设置 Message 的值:

C#复制
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 的值。

cshtml复制
<h3>Msg: @Model.Message</h3> 

Pages/Customers/Index.cshtml.cs 代码隐藏文件将 [TempData] 属性应用到 Message 属性。

C#复制
[TempData]
public string Message { get; set; } 

请参阅 TempData 了解详细信息。

针对一个页面的多个处理程序

以下页面使用 asp-page-handler 标记帮助程序为两个页面处理程序生成标记:

cshtml复制
@page
@model CreateFATHModel<html>
<body><p> Enter your name. </p> <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,因为示例已链接到当前页面。

代码隐藏文件:

C#复制
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

cshtml复制
<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 指令后面添加使用双引号括起来的路由模板来自定义路由。

cshtml复制
@page "{handler?}"
@model CreateRouteModel<html> <body> <p> Enter your name. </p> <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 扩展方法:

C#复制
public void ConfigureServices(IServiceCollection services) { services.AddMvc() .AddRazorPagesOptions(options => { options.RootDirectory = "/MyPages"; options.Conventions.AuthorizeFolder("/MyPages/Admin"); }); } 

目前,可以使用 RazorPagesOptions 设置页面的根目录,或者为页面添加应用程序模型约定。 我们希望将来可以通过这种方式实现更多扩展功能。

转载于:https://www.cnblogs.com/dayang12525/p/7693208.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571774.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于@FeignClient注解实现两个微服务之间接口的调用(简单)

场景需求&#xff1a;微服务A中的接口input需要调用微服务B中接口的output数据。 实现&#xff1a;使用feign实现即可。 微服务B中的接口&#xff1a; 步骤一&#xff1a;微服务A中编写一个接口&#xff0c;该接口就是调用微服务B的接口&#xff1b;需要在接口上添加FeignClien…

Linux lua 性能,systemTab动态分析linux下lua性能

参考ngx-sample-lua-bt现代linux 动态追踪技术 主要是基于 ebpfsystemtap 是 动态追踪的前端&#xff0c; 技术原理是 编译一个 类似c的脚本 生成 内核模块&#xff0c; 来监控用户空间的lua程序对openResty的脚本改造两点&#xff0c;1&#xff1a; 去掉nginx相关函数的 probe…

spring boot 自动跳转登录页面_徒手撸一个扫码登录示例工程

徒手撸一个扫码登录示例工程不知道是不是微信的原因&#xff0c;现在出现扫码登录的场景越来越多了&#xff0c;作为一个有追求、有理想新四好码农&#xff0c;当然得紧跟时代的潮流&#xff0c;得徒手撸一个以儆效尤本篇示例工程&#xff0c;主要用到以下技术栈qrcode-plugin&…

OpenGL, GLSL, DirectX, HLSL中的矩阵存储形式

&#xff08;原文地址&#xff1a;http://alvincc-tech.blogspot.com/2010/10/opengl-glsl-directx-hlsl.html&#xff09; OpenGL, GLSL, DirectX, HLSL中的矩阵存储形式 OpenGL: 按列存储矩阵(column-major)。调用API形成的矩阵用来和一个列向量相乘&#xff0c;矩阵在左&am…

linux cpp标准库,标准库以及标准头文件

源文件通过编译可以生成目标文件(例如 GCC 下的 .o 和 Visual Studio 下的 .obj)&#xff0c;并提供一个头文件向外暴露接口&#xff0c;除了保护版权&#xff0c;还可以将散乱的文件打包&#xff0c;便于发布和使用。实际上我们一般不直接向用户提供目标文件&#xff0c;而是将…

inputstreamreader未关闭会导致oom_ThreadLocal 一定会导致内存泄露?

在面试的时候&#xff0c;ThreadLocal作为高并发常用工具经常会被问到。而面试官比较喜欢问的问题有以下两个&#xff1a;1、ThreadLocal是怎么实现来保证每个线程的变量副本的。2、ThreadLocal的内存泄露是怎么产生的&#xff0c;怎么避免内存泄露。首先我们来看第一个问题&am…

字符串的格式化

字符串作为一种常见的数据类型&#xff0c;也有其不同之处&#xff0c;其中最特别的当属字符串的格式化。 对于“格式化”估计很多的人有点懵&#xff0c;先来看一个例子。 >>> price of eggs: $%d % 3.5 字符串 price of eggs: $3 被格式化后的结果…

学生实验平台搭建c语言程序,c语言程序设计实验学生用.doc

c语言程序设计实验学生用C语言程序设计实验指导(学生用)计算机基础教研室《C语言程序设计》课程组2012年9月前 言《C语言程序设计》是计算机科学技术系面向全校理工科开设地一门专业平台课程.通过这门课程地学习,可以让学生了解程序设计地思想和方法,掌握高级语言程序设计地基本…

keras保存模型_TF2 8.模型保存与加载

举个例子&#xff1a;先训练出一个模型import 接下来第一种方法&#xff1a;只保留模型的参数&#xff1a;这个有2种方法&#xff1a;model.save_weights("adasd.h5")model.load_weights("adasd.h5") model.predict(x_test)model.save_weights(./checkpoin…

第一章 Burp Suite 安装和环境配置

Burp Suite是一个集成化的渗透测试工具&#xff0c;它集合了多种渗透测试组件&#xff0c;使我们自动化地或手工地能更好的完成对web应用的渗透测试和攻击。在渗透测试中&#xff0c;我们使用Burp Suite将使得测试工作变得更加容易和方便&#xff0c;即使在不需要娴熟的技巧的情…

mysql57服务无法启动_将mysqld.service服务加入到systemctl

在开始安装二进制MySQL的时候感觉都还挺好&#xff0c;就是在启动服务的时候比较麻烦&#xff0c;一开始是在Centos6下的感觉也没有什么费劲的;但是在Centos7下面还是有点不太适应&#xff0c;不过还好用用就熟悉了&#xff1b;说明一下&#xff0c;我的安装目录在/usr/local/m…

linux raid autodetect,软raid的建立

1 增加磁盘并分区(修改id)fdisk /dev/sdbCommand (m for help): pDisk /dev/sdb: 8589 MB, 8589934592 bytes255 heads, 63 sectors/track, 1044 cylindersUnits cylinders of 16065 * 512 8225280 bytesDevice Boot Start End Blocks Id System/dev/sd…

input readonly 光标显示问题

input readonly模式下在ie跟火狐访问的时候会有光标会出现&#xff0c;以下方法可解决这个问题 <input type"text" readonly unselectableon onfocus"this.blur()"> 1.unselectableon 是解决ie下光标出现的问题 2.οnfοcus"this.blur() 是解决…

c语言for循环的省略写法,C语言两种for循环写法分析

每个C程序员都知道同一个for循环语句可以有两种写法:A: for (i 0; i B: for (i cnt; i > 0; i--){ }前几天,DEBUG的时候, 发现采用A写法的代码反汇编出来有BUG.当时没有时间记录,环境也没有保存下来.今天尝试重现,又没来出现上次的问题...很奇怪.很久很久以前也听说过这两…

python文字游戏 生成数字菜单_pygame游戏之旅 游戏中添加显示文字

本文为大家分享了pygame游戏之旅的第5篇&#xff0c;供大家参考&#xff0c;具体内容如下 在游戏中添加显示文字&#xff1a; 这里自己定义一个crash函数接口&#xff1a; def crash(): message_diaplay(You Crashed) 然后实现接口函数message_display(text) def message_diapl…

快速排序的改进

package com.txq.test; /*** quicksort,三方面改进&#xff1a;①三数中值选择枢纽元②容量小的时候使用插入排序③重复元素的处理* author XueQiang Tong* date 2017/10/25*/ public class QS {public void quicksort(int []arr,int low,int high){int first low;int last h…

23根火柴游戏 c语言,23 根火柴游戏

#includegt;int main(){int g 23;int k 3;int b, c;printf("这里是23 根火柴游戏&#xff01;&#xff01;\n");printf("注意&#xff1a;最大移动火柴数目为三根\n");do{printf("请输入移动的火柴数目&#xff1a;\n");scanf("%d",…

springboot netty给特定客户端推送_Spring Boot 又升级了?2.0 你搞懂了吗?!

【小宅按】作为知名互联网公司都在用的技术&#xff0c;Spring Boot 2.0 的更新引起了很大的关注&#xff0c;本文将分为三部分解读 2.0 的更新&#xff1a;第一类&#xff0c;基础环境升级&#xff1b;第二类&#xff0c;默认软件替换和优化&#xff1b;第三类&#xff0c;新技…

OSI七层模型与TCP/IP五层模型详解

博主是搞是个FPGA的&#xff0c;一直没有真正的研究过以太网相关的技术&#xff0c;现在终于能静下心学习一下&#xff0c;希望自己能更深入的掌握这项最基本的通信接口技术。下面就开始搞了。 一、OSI参考模型 今天我们先学习一下以太网最基本也是重要的知识——OSI参考模型。…

c是过程化语言吗数据库,关于SQL错误的是()A、所有数据库的公共语言B、非过程化的C、统一的语言D、所有用SQL缩写的程序都...

关于SQL错误的是()A、所有数据库的公共语言B、非过程化的C、统一的语言D、所有用SQL缩写的程序都更多相关问题[多选] 在彩色电视机遥控系统中&#xff0c;属于模拟量控制的有()等几种。[多选] 在色度信号记录处理中&#xff0c;家用录像机一般都要对色度信号经过()等处理。[多选…