ASP.NET Core 中的 Razor 頁面介紹

Razor 頁面是 ASP.NET Core MVC 的一個(gè)新功能,它可以使基于頁面的編碼方式更簡單高效鸿捧。

若要查找使用模型視圖控制器方法的教程泻轰,請(qǐng)參閱 ASP.NET Core MVC 入門铺然。

本文檔介紹 Razor 頁面俗孝。 它并不是分步教程。 如果認(rèn)為某些部分過于復(fù)雜魄健,請(qǐng)參閱 Razor 頁面入門赋铝。 有關(guān) ASP.NET Core 的概述,請(qǐng)參閱 ASP.NET Core 簡介沽瘦。

系統(tǒng)必備

Install one of the following:

創(chuàng)建 Razor 頁面項(xiàng)目

Visual Studio
請(qǐng)參閱 Razor 頁面入門革骨,獲取關(guān)于如何使用 Visual Studio 創(chuàng)建 Razor 頁面項(xiàng)目的詳細(xì)說明农尖。

Visual Studio for Mac
在命令行中運(yùn)行dotnet new razor
在 Visual Studio for Mac 中打開生成的 .csproj 文件良哲。

Visual Studio Code
在命令行中運(yùn)行dotnet new razor盛卡。

.NET Core CLI
在命令行中運(yùn)行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();
    }
}

請(qǐng)考慮一個(gè)基本頁面:

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

上述代碼看上去類似于一個(gè) Razor 視圖文件筑凫。 不同之處在于 @page 指令窟扑。 @page 使文件轉(zhuǎn)換為一個(gè) MVC 操作 ,這意味著它將直接處理請(qǐng)求漏健,而無需通過控制器處理。 @page 必須是頁面上的第一個(gè) Razor 指令橘霎。 @page 將影響其他 Razor 構(gòu)造的行為蔫浆。

將在以下兩個(gè)文件中顯示使用 PageModel 類的類似頁面。 Pages/Index2.cshtml 文件:

@page
@using RazorPagesIntro.Pages
@model IndexModel2

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

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 路徑的關(guān)聯(lián)由頁面在文件系統(tǒng)中的位置決定。 下表顯示了 Razor 頁面路徑及匹配的 URL:

文件名和路徑 匹配的 URL
/Pages/Index.cshtml //Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store/Store/Index

注意:
默認(rèn)情況下处窥,運(yùn)行時(shí)在“Pages”文件夾中查找 Razor 頁面文件嘱吗。
URL 未包含頁面時(shí),Index為默認(rèn)頁面滔驾。

編寫基本窗體

Razor 頁面功能旨在簡化 Web 瀏覽器常用的模式谒麦。 模型綁定標(biāo)記幫助程序和 HTML 幫助程序均只可用于 Razor 頁面類中定義的屬性哆致。 請(qǐng)參考為 Contact 模型實(shí)現(xiàn)基本的“聯(lián)系我們”窗體的頁面:

在本文檔中的示例中绕德,DbContextStartup.cs 文件中進(jìn)行初始化。

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();
        }
    }
}

數(shù)據(jù)模型:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Data
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(100)]
        public string Name { get; set; }
    }
}

數(shù)據(jù)庫上下文:

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

<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 頁面模型:

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 并且它與頁面位于同一個(gè)命名空間中耻蛇。

使用 PageModel 類,可以將頁面的邏輯與其展示分離開來胞此。 它定義了頁面處理程序臣咖,用于處理發(fā)送到頁面的請(qǐng)求和用于呈現(xiàn)頁面的數(shù)據(jù)。 借助這種分離豌鹤,可以通過依賴關(guān)系注入管理頁面依賴關(guān)系亡哄,并對(duì)頁面執(zhí)行單元測試

頁面包含 OnPostAsync 處理程序方法布疙,它在 POST 請(qǐng)求上運(yùn)行(當(dāng)用戶發(fā)布窗體時(shí))蚊惯。 可以為任何 HTTP 謂詞添加處理程序方法愿卸。 最常見的處理程序是:

  • OnGet,用于初始化頁面所需的狀態(tài)截型。 OnGet 示例趴荸。
  • OnPost,用于處理窗體提交宦焦。

Async 命名后綴為可選发钝,但是按照慣例通常會(huì)將它用于異步函數(shù)。 前面示例中的 OnPostAsync 代碼看上去與通常在控制器中編寫的內(nèi)容相似波闹。 前面的代碼通常用于 Razor 頁面酝豪。 多數(shù) MVC 基元(例如模型綁定驗(yàn)證和操作結(jié)果)都是共享的精堕。

之前的 OnPostAsync 方法:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

OnPostAsync 的基本流:

檢查驗(yàn)證錯(cuò)誤孵淘。

  • 如果沒有錯(cuò)誤,則保存數(shù)據(jù)并重定向歹篓。
  • 如果有錯(cuò)誤瘫证,則再次顯示頁面并附帶驗(yàn)證消息。 客戶端驗(yàn)證與傳統(tǒng)的 ASP.NET Core MVC 應(yīng)用程序相同庄撮。 很多情況下背捌,都會(huì)在客戶端上檢測到驗(yàn)證錯(cuò)誤,并且從不將它們提交到服務(wù)器洞斯。

成功輸入數(shù)據(jù)后毡庆,OnPostAsync 處理程序方法調(diào)用 RedirectToPage 幫助程序方法來返回 RedirectToPageResult 的實(shí)例。 RedirectToPage 是新的操作結(jié)果烙如,類似于 RedirectToActionRedirectToRoute扭仁,但是已針對(duì)頁面進(jìn)行自定義。 在前面的示例中厅翔,它將重定向到根索引頁 (/Index)乖坠。 頁面 URL 生成部分中詳細(xì)介紹了 RedirectToPage

提交的窗體存在(已傳遞到服務(wù)器的)驗(yàn)證錯(cuò)誤時(shí)刀闷,OnPostAsync 處理程序方法調(diào)用 Page 幫助程序方法熊泵。Page 返回 PageResult 的實(shí)例。 返回 Page 的過程與控制器中的操作返回 View 的過程相似甸昏。PageResult 是處理程序方法的默認(rèn) 返回類型顽分。 返回 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");
    }
}

默認(rèn)情況下卒蘸,Razor 頁面只綁定帶有非 GET 謂詞的屬性。 綁定屬性可以減少需要編寫的代碼量。 綁定通過使用相同的屬性顯示窗體字段 (<input asp-for="Customer.Name" />) 來減少代碼缸沃,并接受輸入恰起。

備注
出于安全原因,必須選擇綁定 GET 請(qǐng)求數(shù)據(jù)以對(duì)模型屬性進(jìn)行分頁趾牧。 請(qǐng)?jiān)趯⒂脩糨斎胗成涞綄傩郧皩?duì)其進(jìn)行驗(yàn)證检盼。 當(dāng)構(gòu)建依賴查詢字符串或路由值的功能時(shí),選擇加入此行為非常有用翘单。
若要將屬性綁定在 GET 請(qǐng)求上吨枉,請(qǐng)將 [BindProperty] 特性的 SupportsGet 屬性設(shè)置為 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>
            <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 隱藏文件:

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 文件包含以下標(biāo)記來創(chuàng)建每個(gè)聯(lián)系人項(xiàng)的編輯鏈接:

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

定位點(diǎn)標(biāo)記幫助程序 使用 asp-route-{value} 屬性生成“編輯”頁面的鏈接。 此鏈接包含路由數(shù)據(jù)及聯(lián)系人 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" />
    <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 路由數(shù)據(jù)的頁面請(qǐng)求认臊。 如果頁面請(qǐng)求未包含可轉(zhuǎn)換為 int 的路由數(shù)據(jù)属提,則運(yùn)行時(shí)返回 HTTP 404(未找到)錯(cuò)誤。 若要使 ID 可選美尸,請(qǐng)將 ? 追加到路由約束:

@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;

            try
            {
                await _db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                throw new Exception($"Customer {Customer.Id} not found!");
            }

            return RedirectToPage("/Index");
        }
    }
}

Index.cshtml 文件還包含用于為每個(gè)客戶聯(lián)系人創(chuàng)建刪除按鈕的標(biāo)記:

<button type="submit" asp-page-handler="delete" 
        asp-route-id="@contact.Id">delete</button>

刪除按鈕采用 HTML 呈現(xiàn),其 formaction 包括參數(shù):
asp-route-id 屬性指定的客戶聯(lián)系人 ID斟薇。
asp-page-handler 屬性指定的 handler 师坎。

下面是呈現(xiàn)的刪除按鈕的示例,其中客戶聯(lián)系人 ID 為 1

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

選中按鈕時(shí)堪滨,向服務(wù)器發(fā)送窗體 POST 請(qǐng)求胯陋。 按照慣例,根據(jù)方案 OnPost[handler]Async 基于 handler 參數(shù)的值來選擇處理程序方法的名稱袱箱。

因?yàn)楸臼纠?handlerdelete 遏乔,因此 OnPostDeleteAsync 處理程序方法用于處理 POST 請(qǐng)求。 如果 asp-page-handler 設(shè)置為不同值(如 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 查詢客戶聯(lián)系人的數(shù)據(jù)庫了讨。
如果找到客戶聯(lián)系人捻激,則從客戶聯(lián)系人列表將其刪除。 數(shù)據(jù)庫將更新前计。
調(diào)用 RedirectToPage 胞谭,重定向到根索引頁 (/Index) 。

XSRF/CSRF 和 Razor 頁面

無需為防偽驗(yàn)證編寫任何代碼男杈。Razor 頁面自動(dòng)將防偽標(biāo)記生成過程和驗(yàn)證過程包含在內(nèi)丈屹。

將布局、分區(qū)伶棒、模板和標(biāo)記幫助程序用于 Razor 頁面

頁面可使用 Razor 視圖引擎的所有功能旺垒。 布局彩库、分區(qū)、模板袖牙、標(biāo)記幫助程序侧巨、 _ViewStart.cshtml 和 _ViewImports.cshtml 的工作方式與它們?cè)趥鹘y(tǒng)的 Razor 視圖中的工作方式相同。

我們來使用其中的一些功能來整理此頁面鞭达。

向 Pages/_Layout.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>

布局

  • 控制每個(gè)頁面的布局(頁面選擇退出布局時(shí)除外)司忱。
  • 導(dǎo)入 HTML 結(jié)構(gòu),例如 JavaScript 和樣式表畴蹭。

請(qǐng)參閱布局頁面了解詳細(xì)信息坦仍。

在 Pages/_ViewStart.cshtml 中設(shè)置 Layout 屬性:

@{
    Layout = "_Layout";
}

注意:布局位于“頁面”文件夾中。 頁面按層次結(jié)構(gòu)從當(dāng)前頁面的文件夾開始查找其他視圖(布局叨襟、模板繁扎、分區(qū))。 可以從“頁面”文件夾下的任意 Razor 頁面使用“頁面”文件夾中的布局糊闽。

建議不要將布局文件放在“視圖/共享”文件夾中梳玫。 視圖/共享 是一種 MVC 視圖模式。Razor 頁面旨在依賴文件夾層次結(jié)構(gòu)右犹,而非路徑約定提澎。

Razor 頁面中的視圖搜索包含“頁面”文件夾。 用于 MVC 控制器和傳統(tǒng) Razor 視圖的布局念链、模板和分區(qū)可直接工作盼忌。

添加 Pages/_ViewImports.cshtml 文件:

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

本教程的后續(xù)部分中將介紹 @namespace@addTagHelper 指令將內(nèi)置標(biāo)記幫助程序引入“頁面”文件夾中的所有頁面掂墓。

頁面上顯式使用 @namespace 指令后:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

此指令將為頁面設(shè)置命名空間谦纱。 @model 指令無需包含命名空間。
_ViewImports.cshtml 中包含 @namespace 指令后君编,指定的命名空間將為在導(dǎo)入 @namespace 指令的頁面中生成的命名空間提供前綴跨嘉。 生成的命名空間的剩余部分(后綴部分)是包含 _ViewImports.cshtml 的文件夾與包含頁面的文件夾之間以點(diǎn)分隔的相對(duì)路徑。

例如吃嘿,代碼隱藏文件 Pages/Customers/Edit.cshtml.cs 顯式設(shè)置命名空間:

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

Pages/_ViewImports.cshtml 文件設(shè)置以下命名空間:

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

為 Pages/Customers/Edit.cshtml Razor 頁面生成的命名空間與代碼隱藏文件相同. 已對(duì) @namespace 指令進(jìn)行設(shè)計(jì)偿荷,因此添加到項(xiàng)目的 C# 類和頁面生成的代碼可直接工作,而無需添加代碼隱藏文件的 @using 指令唠椭。

注意: @namespace 也可用于傳統(tǒng)的 Razor 視圖跳纳。

原始的 Pages/Create.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 視圖文件:

@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>

頁面的 URL 生成

之前顯示的 Create 頁面使用 RedirectToPage

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

應(yīng)用具有以下文件/文件夾結(jié)構(gòu):

  • /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”文件夾到頁面的路徑(包含前導(dǎo) / 斗塘,例如 /Index )赢织。相較于僅對(duì) URL 硬編碼,前面的 URL 生成示例的功能更加強(qiáng)大馍盟。URL 生成使用路由于置,并且可以根據(jù)目標(biāo)路徑定義路由的方式生成參數(shù)并對(duì)參數(shù)編碼。

頁面的URL生成支持相對(duì)名稱贞岭。 下表顯示了 Pages/Customers/Create.cshtml 中不同的 RedirectToPage 參數(shù)選擇的索引頁:

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") 是相對(duì)名稱。 結(jié)合 RedirectToPage 參數(shù)與當(dāng)前頁的路徑來計(jì)算目標(biāo)頁面的名稱瞄桨。

構(gòu)建結(jié)構(gòu)復(fù)雜的站點(diǎn)時(shí)话速,相對(duì)名稱鏈接很有用。 如果使用相對(duì)名稱鏈接文件夾中的頁面芯侥,則可以重命名該文件夾泊交。 所有鏈接仍然有效(因?yàn)檫@些鏈接未包含此文件夾名稱)。

TempData

ASP.NET在控制器上公開了 TempData 屬性柱查。 此屬性存儲(chǔ)未讀取的數(shù)據(jù)廓俭。 KeepPeek 方法可用于檢查數(shù)據(jù),而不執(zhí)行刪除唉工。 多個(gè)請(qǐng)求需要數(shù)據(jù)時(shí)研乒, TempData 有助于進(jìn)行重定向。

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

下面的代碼使用 TempData 設(shè)置 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 文件中的以下標(biāo)記使用 TempData 顯示 Message 的值错维。

<h3>Msg: @Model.Message</h3>

Pages/Customers/Index.cshtml.cs頁面模型將[TempData]屬性應(yīng)用到Message屬性奖地。

[TempData]
public string Message { get; set; }

請(qǐng)參閱 TempData 了解詳細(xì)信息。

針對(duì)一個(gè)頁面的多個(gè)處理程序

以下頁面使用 asp-page-handler 標(biāo)記幫助程序?yàn)閮蓚€(gè)頁面處理程序生成標(biāo)記:

@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>

前面示例中的窗體包含兩個(gè)提交按鈕赋焕,每個(gè)提交按鈕均使用 FormActionTagHelper 提交到不同的 URL 参歹。 asp-page-handlerasp-page 的配套屬性。 asp-page-handler 生成提交到頁面定義的各個(gè)處理程序方法的 URL 隆判。未指定 asp-page 犬庇,因?yàn)槭纠焰溄拥疆?dāng)前頁面。

頁面模型:

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 之前的文本(如果有)創(chuàng)建臭挽。 在前面的示例中,頁面方法是 OnPostJoinListAsync 和 OnPostJoinListUCAsync 咬腕。刪除 OnPost 和 Async 后欢峰,處理程序名稱為 JoinListJoinListUC

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

使用前面的代碼時(shí),提交到 OnPostJoinListAsync 的 URL 路徑為 http://localhost:5000/Customers/CreateFATH?handler=JoinList 纽帖。提交到 OnPostJoinListUCAsync 的 URL 路徑為 http://localhost:5000/Customers/CreateFATH?handler=JoinListUC 宠漩。

自定義路由

如果你不喜歡 URL 中的查詢字符串 ?handler=JoinList,可以更改路由懊直,將處理程序名稱放在 URL 的路徑部分扒吁。可以通過在 @page 指令后面添加使用雙引號(hào)括起來的路由模板來自定義路由室囊。

@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 前面的 ? 表示路由參數(shù)為可選波俄。

可以使用 @page 將其他段和參數(shù)添加到頁面的路由中晨逝。 其中的任何內(nèi)容均會(huì)被追加到頁面的默認(rèn)路由中。 不支持使用絕對(duì)路徑或虛擬路徑更改頁面的路由(如 "~/Some/Other/Path" )懦铺。

配置和設(shè)置

若要配置高級(jí)選項(xiàng)捉貌,請(qǐng)?jiān)?MVC 生成器上使用 AddRazorPagesOptions 擴(kuò)展方法:

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

目前,可以使用 RazorPagesOptions 設(shè)置頁面的根目錄冬念,或者為頁面添加應(yīng)用程序模型約定趁窃。 通過這種方式,我們?cè)趯頃?huì)實(shí)現(xiàn)更多擴(kuò)展功能急前。

若要預(yù)編譯視圖醒陆,請(qǐng)參閱 Razor 視圖編譯

下載或查看示例代碼.

請(qǐng)參閱 Razor 頁面入門裆针,這篇文章以本文為基礎(chǔ)編寫刨摩。

指定 Razor 頁面位于內(nèi)容根目錄中

默認(rèn)情況下,Razor 頁面位于 /Pages 目錄的根位置世吨。向 AddMvc 添加 WithRazorPagesAtContentRoot澡刹,以指定 Razor 頁面位于應(yīng)用的內(nèi)容根目錄 (ContentRootPath) 中:

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesAtContentRoot();

指定 Razor 頁面位于自定義根目錄中

AddMvc 添加 WithRazorPagesRoot,以指定 Razor 頁面位于應(yīng)用中自定義根目錄位置(提供相對(duì)路徑):

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesRoot("/path/to/razor/pages");

請(qǐng)參閱

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耘婚,一起剝皮案震驚了整個(gè)濱河市罢浇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌沐祷,老刑警劉巖嚷闭,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赖临,居然都是意外死亡胞锰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門兢榨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胜蛉,“玉大人挠进,你說我怎么就攤上這事√懿幔” “怎么了领突?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長案怯。 經(jīng)常有香客問我君旦,道長,這世上最難降的妖魔是什么嘲碱? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任金砍,我火速辦了婚禮,結(jié)果婚禮上麦锯,老公的妹妹穿的比我還像新娘恕稠。我一直安慰自己,他們只是感情好扶欣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布鹅巍。 她就那樣靜靜地躺著,像睡著了一般料祠。 火紅的嫁衣襯著肌膚如雪骆捧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天髓绽,我揣著相機(jī)與錄音敛苇,去河邊找鬼。 笑死顺呕,一個(gè)胖子當(dāng)著我的面吹牛枫攀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播株茶,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼来涨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了忌卤?” 一聲冷哼從身側(cè)響起扫夜,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤楞泼,失蹤者是張志新(化名)和其女友劉穎驰徊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堕阔,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棍厂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了超陆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牺弹。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浦马,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出张漂,到底是詐尸還是另有隱情晶默,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布航攒,位于F島的核電站磺陡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏漠畜。R本人自食惡果不足惜币他,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望憔狞。 院中可真熱鬧蝴悉,春花似錦、人聲如沸瘾敢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽廉丽。三九已至倦微,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間正压,已是汗流浹背欣福。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焦履,地道東北人拓劝。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像嘉裤,于是被迫代替她去往敵國和親郑临。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容