天天看點

asp.net core系列 39 Razor 介紹與詳細示例

asp.net core系列 39 Razor 介紹與詳細示例

一. Razor介紹

  在使用ASP.NET Core Web開發時, ASP.NET Core MVC 提供了一個新特性Razor。 這樣開發Web包括了MVC架構和Razor架構。對于Razor來說它是一個新特性,在官方介紹ASP.NET Core的優點中提到“Razor Pages可以使基于頁面的編碼方式更簡單高效”。

  1.1 Razor結構介紹

    (1) Pages檔案夾

                            存放所有Razor頁面,包括Razor 頁面和支援檔案。 每個 Razor 頁面都是一對檔案:

                            一個 .cshtml 檔案,其中包含使用 Razor 文法的 C# 代碼的 HTML 标記。

                            一個 .cshtml.cs 檔案,其中包含處理頁面事件的 C# 代碼。

                     支援檔案的名稱以下劃線開頭。 例如,_Layout.cshtml 檔案可配置所有頁面通用的 UI 元素。 此檔案設定頁面頂部的導航菜單和頁面底部的版權聲明(後面講布局時再介紹)。

    (2) wwwroot 檔案夾

                            包含靜态檔案,如 HTML 檔案、JavaScript 檔案和 CSS 檔案(後面再講)。

    (3) appSettings.json

                            包含配置資料,如連接配接字元串。參考asp.net core 系列第 10和11篇

    (4) Program.cs

                            包含程式的入口點,啟動主機。參考asp.net core 系列第 16和17篇

    (5) startup.cs

                            包含配置應用行為的代碼,例如,是否需要同意 cookie。參考asp.net core 系列第 2篇

asp.net core系列 39 Razor 介紹與詳細示例

    

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

   1.3  @page指令

    對于每一個Razor 頁面,在.cshtml視圖檔案中,@page指令必須是頁面上的第一個 Razor 指令。@page 使檔案轉換為一個 MVC 操作 ,這意味着它将直接處理請求, 而不通過控制器(Controllers)處理。

@page

 将影響其他 Razor 構造的行為。下面是一個直接處理請求的示例:

//index.cshtml.cs 
    public class IndexModel : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        //加載時調用
        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }    

    //Index.cshtml,直接輸出後端的Message屬性資訊,也這是Razor的優勢,使用頁面的編碼方式更簡單高效。
    @page
    @using RazorPagesIntro.Pages
    @model IndexModel

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

  1.4 頁面url路徑

    URL路徑是與頁面的關聯,由頁面在檔案系統中的位置決定,下表顯示了Razor Page路徑和比對的URL:

檔案路徑 通路網址
/Pages/Index.cshtml

/

     or     

/Index

/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml

/Store 

 or  

/Store/Index

二. 完整示例介紹

  

  2.1 安裝EF資料提供程式

    這裡使用記憶體資料庫Microsoft.EntityFrameworkCore.InMemory,Entity Framework Core 和記憶體資料庫一起使用, 這對測試非常有用。

    PM> Install-Package Microsoft.EntityFrameworkCore.InMemory      

    

  2.2 建立資料模型類(POCO )和EF上下文類 

public class Customer
    {
        public int Id { get; set; }

         //儲存不能為空,字元長度小于100
        [Required, StringLength(100)]
        public string Name { get; set; }
    }

   public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }      

  2.3 啟動類關鍵代碼

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

  2.4 新增頁 Pages/Create

@page
@model StudyRazorDemo.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <!-- 這裡的Customer對象來自後端-->
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>      
public class CreateModel : PageModel
    {
        private readonly AppDbContext _db;

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

        //模型綁定,通過綁定使用相同的屬性顯示窗體字段<input asp-for="Customer.Name" />來減少代碼,并接受輸入,是雙向綁定。
        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            //驗證Customer對象屬性值
            if (!ModelState.IsValid)
            {
                return Page();
            }

            //添加到EF上下文,再儲存到記憶體資料庫
            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();

            // 重定向到index首頁
            return RedirectToPage("/Index");
        }
    }      

  點選送出後,cs後端的Customer對象将自動綁定來自前端轉來的值,如下圖所示:

asp.net core系列 39 Razor 介紹與詳細示例

  

  2.5 查詢首頁Pages/Index 關鍵代碼

<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            <!--Customers集合對象來自cs後端 -->
            @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>      
public IList<Customer> Customers { get; private set; }

        //代替OnGet方法
        public async Task OnGetAsync()
        {
            //異步擷取資料,EF上下文不跟蹤該集合對象
            Customers = await _db.Customers.AsNoTracking().ToListAsync();
        }      

    所有asp- 開頭的都是TagHelper内置标記,查詢如下圖所示:

asp.net core系列 39 Razor 介紹與詳細示例

  2.6 修改頁Pages/Edit關鍵代碼

    在首頁中(<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a> )是導航到編輯頁。例如:http://localhost:5000/Edit/1。

    第一行包含 

@page "{id:int}"

 指令,是用來路由限制,如果頁面請求未包含可轉換為 

int

 的路由資料,則運作時傳回 HTTP 404。若要使 ID可選,請将 

?

 追加到路由限制( @page "{id:int?}" )

@page "{id:int}"

@model StudyRazorDemo.Pages.EditModel

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<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" />

            <!--後端驗證Name,當失敗時提示錯誤資訊 -->
            <span asp-validation-for="Customer.Name"></span>
        </div>
    </div>

    <div>
        <button type="submit">Save</button>
    </div>
</form>      
[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");
        }      

    通過ID來修改資料,如下圖所示:

asp.net core系列 39 Razor 介紹與詳細示例

  2.7 删除 Pages/index

     删除動作是在index頁面完成。使用處理事件asp-page-handler="delete" 來指定後端的action 為delete方法處理。 按照約定,方法命名為: 

OnPost[handler]Async

 ,方法參數為 asp-route-id傳來的值。

/// <summary>
        /// index後端,根據ID删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        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();
        }      

  

 參考文獻

  詳細的razor教程

   razor 頁面介紹

  

posted on 2019-03-08 10:17 花陰偷移 閱讀(...) 評論(...) 編輯 收藏