Day03 - Razor Pages


什麼是 Razor Pages ?

過去我們常用MVC的架構來建立我們的專案,但有時候我們的專案只是想要實現一個簡單的小功能,若使用 MVC 好像有點顯得過於複雜。這時,我們可以選擇 Razor Pages
MVC 代表著 Models、View、Controller。Model 存放我們的資料模型;View 是一個存放 HTML 與 Tag Helper 的cshtml檔;Controller 則存放邏輯。而 Razor Pages 就是一個讓我們可以將這三個元素定義在一起的 View。

實作要點

Startup.cs

首先我們在 Startup.cs 的 ConfigureServices method 中添加 Razor Pages。

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages(); // 加入這行
    services.AddSingleton<IConferenceService, ConferenceMemoryService>();
    services.AddSingleton<IProposalService, ProposalMemoryService>();
}

而在 Configure method中,選擇使用 razor pages 來決定這個專案的 endpoint。所以加入了這行endpoints.MapRazorPages()程式後,專案的 endpoint 會由專案目錄底下的 Pages 目錄裡面的 cshtml 檔來決定。但網址並不需要加入.cshtml。舉例來說,目錄底下的 .../Pages/Index.cshtml 則對應到的URL為 .../Index 或是 .../

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseCookiePolicy();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Shard/_Layout.cshtml

定義我們常用共用的 layout。

_ViewStart.cshtml

而上面定義的 layouts 由 ViewStart 決定啟用哪個 layout 。

DisplayTemplates/xxx.cshtml

定義一些我們常用重複使到的 templates。

xxx.cshtml

@page
@using GlobomanticsRazorPages.Services
@using GlobomanticsRazorPages.Models
@inject IConferenceService conferenceService

<div class="row">
    <div class="col-md-10 col-md-offset-2">
        <table class="table">
            <tr>
                <th>Name</th>
                <th>Location</th>
                <th>Start of event</th>
                <th>Attendees</th>
                <th>Actions</th>
            </tr>
            @Html.DisplayFor(m => m.Conferences)
        </table>
    </div>
</div>
<div class="row">
    <div class="col-md-4">
        <a asp-page="Conferences/AddConference">Add</a>
    </div>
</div>

@functions {
        public IEnumerable<ConferenceModel> Conferences { get; private set; }

        public async Task OnGet()
        {
            Conferences = await conferenceService.GetAll();
        }
}

可以看到上面程式第四行 @inject IConferenceService conferenceService ,我們可以使用關鍵字@inject來注入我們的Service。
還有一點不同的是, <a asp-page="Conferences/AddConference">Add</a> ,可以看到我們使用的是 <a asp-page=...> 這個tag,來導向我們定義好的Pages。
而最下面我們可以看到由Razor定義的function @functions

若你是不喜歡把functions寫在HTML下面的人,你可以把這些function寫在 xxx.cshtml.cs 裡面,而這個cs檔繼承 PageModel 就可以囉,如下:

using System.Threading.Tasks;
using GlobomanticsRazorPages.Models;
using GlobomanticsRazorPages.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace GlobomanticsRazorPages.Pages
{
    public class AddConferenceModel : PageModel
    {
        private readonly IConferenceService conferenceService;

        [BindProperty]
        public ConferenceModel Conference { get; set; }

        public AddConferenceModel(IConferenceService conferenceService)
        {
            this.conferenceService = conferenceService;
        }

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

            await conferenceService.Add(Conference);
            return RedirectToPage("/Index");
        }
    }

另外可以看到上面的ConferenceModel Conference,使用了BindProperty。這讓我們在cshtml可以直接去使用Conference。如下:

@page
@model GlobomanticsRazorPages.Pages.AddConferenceModel
    <form method="post">
        <div class="row form-group">
            <div class="col-md-2 col-md-offset-2">
                <label asp-for="Conference.Name"></label>
            </div>
            <div class="col-md-2">
                <input class="form-control" asp-for="Conference.Name" />
            </div>
        </div>
        <div class="row form-group">
            <div class="col-md-2 col-md-offset-2">
                <label asp-for="Conference.Location"></label>
            </div>
            <div class="col-md-2">
                <input class="form-control" asp-for="Conference.Location" />
            </div>
        </div>
        <div class="row form-group">
            <div class="col-md-2 col-md-offset-2">
                <label asp-for="Conference.Start"></label>
            </div>
            <div class="col-md-2">
                <input class="form-control" type="date" asp-for="Conference.Start" />
            </div>
        </div>
        <div class="row form-group">
            <div class="col-md-2 col-md-offset-2">
                <label asp-for="Conference.AttendeeTotal"></label>
            </div>
            <div class="col-md-2">
                <input class="form-control" type="number" asp-for="Conference.AttendeeTotal" />
            </div>
        </div>
        <div class="row">
            <div class="col-md-2 col-md-offset-4">
                <button type="submit" class="btn btn-primary">Add</button>
            </div>
        </div>
    </form>

可以看到要存取Conference的值,只要用 Conference.xxx 就可以了,是不是很方便!

結語

今天小簡介了 Razor Pages 的架構。我也是邊學邊做筆記的,有錯誤還麻煩各位大大指正,感恩!!







Related Posts

兩年過後,我能夠被稱為資深工程師了嗎?

兩年過後,我能夠被稱為資深工程師了嗎?

簡明 Linux Shell Script 入門教學

簡明 Linux Shell Script 入門教學

[MTR04] W0 D1 看 Lidemy 課程影片

[MTR04] W0 D1 看 Lidemy 課程影片

#001_0612 始まる。

#001_0612 始まる。

Git 基礎概念與版本控制操作

Git 基礎概念與版本控制操作

初探網頁前後端架構

初探網頁前後端架構



Comments