ASP.NET Core 2.0 的 Razor page 上集

  • 4985
  • 0
  • 2017-11-09

時間真的過的很快,2017年都快過了一半.按照產品的時程,夏天便是 ASP.NET Core 2.0 的釋出時間了.回想起來,我連 1.1 版本裡還有許多東西都尚未記錄下來,產品釋出時程將快來到 2.0 了.在 2.0 版裡也是有許多新東西,其中有一個新東西跟 View 有關,它叫 Razor page,有興趣的朋友請看內文.

Razor page 是 ASP.NET Core MVC framework 裡面的一部份,因為我的工作內容完全跟 MVC framework 扯不上任何關係,所以我也不太會注意 MVC framework 裡有什麼新東西.之前只記錄過 Tag Helper 上集下集,因為當時我覺得這東西應該對許多 ASP.NET MVC 開發者很有用處,它讓你可以定義自己的 tag,可以寫自己的邏輯來處理自己的需求.因為這樣的好處,所以才特別記錄它.Razor page 也是這次在 MVC framework 裡看到一個特別的新東西,但這次它反而不像是 MVC,感覺比較像是以前的 Web Pages.接下來就來看看它的內容.

工具

在寫這篇文章的時候,相關的工具都仍在 preview 版本,得等到 8 月初時才會有正式版釋出.儘管如此,這些 preview 版的工具已經都能下載試用.使用 Razor page,你需要的工具如下:

1. Visual Studio 2017 Update 3 preview

2. .Net Core SDK 2.0 preview

ASP.NET Core 2.0 將運作在 .Net Core 2.0 上,所以 .Net Core 2.0 是需要的.使用 Visual Studio 2017 是讓你可以得到工具的幫助,不用從頭把每個檔案都自己建立.

在 Visual Studio 2017 中有了新的範本引擎,同時新版的範本引擎在 ASP.NET Core 2.0 帶來以下的範本.

除了 Razor page 的範本以外,你可以看到 Angular 和 react.js 的範本也加進來了.這點應該還蠻酷的! 開啟了 Razor page 的範本之後,你可以看到整個專案結構如下:

相信眼尖的你已經看到了 Model 和 Controller 的資料夾不見了.Model 不見也就算了,怎麼連 Controller 也不見了呢 ? 它真的不見了,因為 Razor page 不再需要 controller 來做為 routing 用途,而是以每個 page 為一個單位來使用.這也就是之前說感覺好像是 Web Pages 一樣.預設上,Razor page 都將被放在 Pages 資料夾裡,這是 MVC framework 預設用來找 Razor page 的地方,所以對 Rage page 來說,Pages 資料夾就彷佛是 wwwroot 的位置.Page 的載入跟以前來比並沒有什麼改變,MVC framework 仍會尋找 _ViewStart.cshtml,從它開始載入所有相關的資源.預設上 _ViewStart.cshtml 會載入 _Layout.cshtml.將 _Layout.cshtml 打開後,可以看到大部份的內容都跟前一個版本一樣,但細看之後可以發現一個變化.<a> 的 tag helper 有一個新屬性 (asp-page) 讓我們可以指定要去那一個 Razor page.

                
<ul class="nav navbar-nav">
<li><a asp-page="/Index">Home</a></li>
<li><a asp-page="/About">About</a></li>
<li><a asp-page="/Contact">Contact</a></li>
</ul>

你可以看到,這裡已經不需要指定 Controller 和 Action 了.

@Page

以下是 Contact.cshtml 的內容


@page
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}
<h2>@ViewData["Title"].</h2>
<h3>@Model.Message</h3>

<address>
    One Microsoft Way<br />
    Redmond, WA 98052-6399<br />
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br />
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

在第一行看到了一個新的指令 @page.透過它用來設定整個頁面的內容是一份 Razor page.在 MVC 的寫法裡,你知道第二行的 ContactModel 可以從 Controller 帶過來,但現在沒有 Controller 了,它是怎麼來的呢 ? 原來是透過 code-behind 過來的.在 VS2017 上將 Contact.cshtml 展開後,你會看到

再開啟 Contact.cshtml.cs 的內容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApplication6.Pages
{
    public class ContactModel : PageModel
    {
        public string Message { get; set; }

        public void OnGet()
        {
            Message = "Your contact page.";
        }
    }
}

相信許多開發者都應該用過 ASP.NET Web Pages,看到這裡,是不是覺得好像 Web Pages 呢! 這裡有個神奇的 method - OnGet(),它是在這個 page 透過 HTTP Get 讀取時所會執行的 method,因此在網頁上,我們才會看到 "Your contact page." 這字串出現在畫面上,它就是從這裡來的.如果改成下一個更簡單的例子:

@page
@functions {
    public IActionResult OnGet()
    {
        Message = "From OnGet";
        return Page();
    }
    public string Message { get; set; } = "Default";
}
The message: @Message

這個例子直接將 code-behind c# code 和前端 HTML 全部寫在一起,當你用 HTTP Get 來觀看這頁面時,你將會看到 "From OnGet" 這個字串,若用 Post 方式來觀看,看到的字串將是 "Default".這時候,也許你會猜是不是會有 OnPost()! 沒錯,真的有! 下面是一個簡單的例子.

@page
@functions
{
    public IActionResult OnPost(int value) => RedirectToPage(new { user = value });
}

<form action="">
    // 省略...
</form>

我們將前面的 Contact.cshtml.cs 的內容改成如下:

    public class ContactModel : PageModel
    {
        public string Message { get; set; }

        public void OnGet(string message)
        {
            Message = message;
        }

        public void OnPost()
        {
            Message = "You posted!";
        }
    }

OnGet() 的 message 是透過 URL 的 query string 來的,例如輸入 http://localhost:49894/Contact?message=hello,這樣 message 就會變成 "hello" 字串出現在網頁上.Razor page 可以讓把你 c# 程式和 HTML 內容放在一起,也可以分開不同的檔案裡,如果你寫 MVC 習慣了,可能把 C# code 和 HTML 分離才是你習慣的方式.就如同前面幾個簡單的例子一樣,都是用分開的方式來撰寫.在撰寫 Razor page 的 model class 時,從上面的例子中都可以看到有一個特別的東西 - PageModel.

PageModel

PageModel 可說是 Razor page 功能裡很重要的 class.它的原始程式碼可在這連結找到.從它所定義的方法與屬性來看,你就能清楚地看到它所擁有的能力是什麼,例如存取 HttpContext (HttpRequest 與 HttpResponse 的內容), temp data 的操作, 頁面之間的 redirection,security 內容的處理等等,全部都在這個 class 裡.內容可以說是包山包海,把你撰寫網頁時所需要的能力都加了進來.以上一個例子來說,當 ContractModel 繼承了 PageModel 之後,也同樣有了這些能力.以 page reidrection 來說,PageModel 提供了許多 methods 可以執行 page redirection,而前面已經列出其中一個 page redirection 的例子.下面是另一個使用 temp data 的例子.

    
public class SetTempDataPageModel: PageModel
    {
        public IActionResult OnGet(string message)
        {
            TempData["Message"] = message;
            return Redirect("~/TempData/ShowMessage");
        }
    }

TempData 是 PageModel 裡提供用來在 page 之間傳送資料的一種方法,以上的例子是在 OnGet() 裡設定了一個 TempData,然後導向到另外一個 Razor page 後就可以透過 TempData 將 message 內容讀取出來.

以上內容是最簡單的 Razor page 介紹,等我對它了解更多內容之後,再來記錄更多有關它的事情.

Hope it helps,