推薦使用 Razor Pages在 [ASP.NET](http://ASP.NET) Core MVC 框架中創建 UI。
首先,在ProductManagement.Web項目的*Pages*文件夾下創建一個*Products文件夾。然后,右鍵單擊Products*文件夾,然后選擇**Add**|**Razor Page**。選擇**Razor 頁面 - 空**選項,命名為`Index.cshtml`。下圖顯示了我們添加的頁面的位置:

編輯內容,`Index.cshtml`如下代碼塊所示:
```
@page
@using ProductManagement.Web.Pages.Products
@model IndexModel
<h1>Products Page</h1>
```
在這里,我放置一個`h1`元素作為頁眉。接下來我們在主菜單中添加一個菜單來打開這個頁面。
## 添加菜單項
ABP 提供了一個動態、模塊化的菜單系統。每個模塊都可以添加到主菜單。
打開*ProductManagement.Web項目的\*\*Menus*文件夾中的`ProductManagementMenuContributor`類,并在`ConfigureMainMenuAsync`方法末尾添加以下代碼:
```
context.Menu.AddItem(
????new ApplicationMenuItem(
????????"ProductManagement",
????????l["Menu:ProductManagement"],
????????icon: "fas fa-shopping-cart"
????????????).AddItem(
????????new ApplicationMenuItem(
????????????"ProductManagement.Products",
????????????l["Menu:Products"],
????????????url: "/Products"
????????)
????)
);
```
此代碼添加了一個*產品管理*主菜單,其中包含產品菜單項。里面的`l["…"]`語法是用來獲取本地化的值。
打開ProductManagement.Domain.Shared 項目的Localization/ProductManagement文件夾中的`en.json`文件,并將以下代碼添加到該`texts`部分的末尾:
```
"Menu:ProductManagement": "Product Management",
"Menu:Products": "Products"
```
我們可以使用任意字符串值作為本地化鍵。在本例中,我們使用`Menu:`作為菜單的本地化鍵的前綴,例如`Menu:Products` 。我們將在\[*第 8 章*\] *使用 ABP 的功能和服務*中探討本地化主題。
現在,重新運行,使用新的*產品管理*菜單打開*產品*頁面,如圖所示:

## 創建產品數據表
接下來我們將創建一個數據表顯示帶有分頁和排序的產品列表。ABP 啟動模板帶有預安裝和配置的JS 庫 [**Datatables.net**](http://Datatables.net),用于顯示表格數據。
打開`Index.cshtml`頁面(在*Pages/Products*文件夾),并將其內容更改為以下內容:
```
@page
@using ProductManagement.Web.Pages.Products
@using Microsoft.Extensions.Localization
@using ProductManagement.Localization
@model IndexModel
@inject IStringLocalizer<ProductManagementResource> L
@section scripts
{
????<abp-script src="/Pages/Products/Index.cshtml.js" />
}
<abp-card>
????<abp-card-header>
????????<h2>@L["Menu:Products"]</h2>
????</abp-card-header>
????<abp-card-body>
????????<abp-table id="ProductsTable" striped-rows="true" />
????</abp-card-body>
</abp-card>
```
`abp-script`是一個 ABP 標簽助手,用于將腳本文件添加到頁面,并具有自動捆綁、壓縮和版本控制功能。`abp-card`是另一個標簽助手,以一種類型安全且簡單的方式渲染 Card 組件。
> 我們可以使用標準的 HTML 標簽。但是,ABP 標簽助手極大地簡化了 MVC/Razor 頁面中的 UI 創建。此外,它們支持智能感知和編譯時錯誤類型檢查。我們將在\[*第 12 章*\] *使用 MVC/Razor 頁面*中研究標簽助手。
*在Pages/Products*文件夾下創建一個新的 JavaScript 文件,命名為`Index.cshtml.js`,內容如下:
```
$(function () {
????var l = abp.localization.getResource('ProductManagement');
????var dataTable = $('#ProductsTable').DataTable(
????????abp.libs.datatables.normalizeConfiguration({
????????????serverSide: true,
????????????paging: true,
????????????order: [[0, "asc"]],
????????????searching: false,
????????????scrollX: true,
????????????ajax: abp.libs.datatables.createAjax(
????????????????productManagement.products.product.getList),
????????????columnDefs: [
????????????????/* TODO: Column definitions */
????????????]
????????})
????);
});
```
ABP 簡化了數據表配置并提供了內置集成:
* `abp.localization.getResource` 返回一個本地化對象,ABP 允許您在 JS中重用服務器端定義的本地化。
* `abp.libs.datatables.normalizeConfiguration`是 ABP 框架定義的輔助函數。它通過為缺失選項提供常規默認值來簡化數據表的配置。
* `abp.libs.datatables.createAjax` 使 ABP 的動態 JS 客戶端代理來適配數據表的參數格式。
* `productManagement.products.product.getList`是動態JS代理方法。
`columnDefs`數組用于定義數據表中的列:
```
{
????title: l('Name'),
????data: "name"
},
{
????title: l('CategoryName'),
????data: "categoryName",
????orderable: false
},
{
????title: l('Price'),
????data: "price"
},
{
????title: l('StockState'),
????data: "stockState",
????render: function (data) {
????????return l('Enum:StockState:' + data);
????}
},
{
????title: l('CreationTime'),
????data: "creationTime",
????dataFormat: 'date'
}
```
通常,列有一個`title`字段和一個`data`字段。`data`字段匹配`ProductDto`類中的屬性名稱,格式為**駝峰**式(一種命名風格,其中每個單詞的第一個字母大寫,第一個單詞除外;它是JavaScript 語言中常用的命名風格)。
該`render`選項用于精細控制如何顯示列數據。
在此頁面上,我們使用了一些本地化鍵。我們應該先在本地化資源中定義它們。打開ProductManagement.Domain.Shared項目的*Localization/ProductManagement* *文件*夾中的`en.json`文件,并在該部分的末尾添加以下條目`texts`:
```
"Name": "Name",
"CategoryName": "Category name",
"Price": "Price",
"StockState": "Stock state",
"Enum:StockState:0": "Pre-order",
"Enum:StockState:1": "In stock",
"Enum:StockState:2": "Not available",
"Enum:StockState:3": "Stopped",
"CreationTime": "Creation time"
```
看一下實際的產品數據表:

至此,我們創建了一個完整的工作頁面,列出了支持分頁和排序的產品。在接下來的部分中,我們將添加創建、編輯和刪除產品的功能。
- 前言
- 第一部分
- 第1章 現代軟件開發和 ABP 框架
- 企業級 Web 開發的挑戰
- ABP框架的能力清單
- 第2章 ABP框架入門
- 安裝 ABP CLI
- 創建新解決方案
- 運行解決方案
- 探索預構建模塊
- 第3章 逐步開發開發ABP應用
- 創建解決方案
- 定義領域對象
- EFCore和數據庫映射
- 定義應用服務
- 測試產品
- 產品列表
- 創建產品
- 編輯產品
- 刪除產品
- 第4章 探索 EventHub解決方案
- 應用介紹
- 架構探索
- 方案運行
- 第二部分
- 第5章 探索ABP基礎架構
- 了解模塊化
- 使用依賴注入系統
- 配置應用程序
- 實現選項模式
- 日志系統
- 第6章 數據訪問基礎架構
- 定義實體
- 定義倉儲庫
- EF Core集成
- 了解 UoW
- 第7章 探索橫切關注點
- 認證授權
- 用戶驗證
- 異常處理
- 第8章 體驗 ABP 的功能和服務
- 獲取當前用戶
- 使用數據過濾
- 控制審計日志
- 緩存數據
- 本地化用戶界面
- 第三部分
- 第9章 理解領域驅動設計
- 介紹 DDD
- 構建基于 DDD 的 解決方案
- 處理多個應用程序
- 了解執行流程
- DDD的通用原則
- 第10章 領域層 Domain
- 領域事件案例分析
- 聚合和實體的設計原則和實踐
- 實現領域服務
- 落地存儲庫
- 構建規約(Specification)
- 領域事件
- 第11章 應用層 Application
- 落地應用服務
- 設計 DTO
- 理解各層的職責
- 第四部分
- 第12章 MVC/Razor 頁面
- 主題系統
- 綁定和壓縮
- 導航菜單
- Bootstrap標簽助手
- 創建表單并驗證
- 使用模態窗口
- 使用JS API
- 調用HTTP API
- 第13章 Blazor WebAssembly UI
- 什么是Blazor
- ABP Blazor UI
- 驗證用戶身份
- 理解主題系統
- 使用菜單
- 使用基本服務
- 使用UI服務
- 消費HTTP API
- 使用全局腳本和樣式
- 第14章 HTTP API 和實時服務
- 構建HTTP API
- 使用HTTP API
- 使用SignalR
- 第五部分
- 第15章 落地模塊化
- 理解模塊化
- 構建支付模塊
- 安裝模塊
- 第16章 實現多租戶
- 理解多租戶
- 多租戶基礎設施
- 使用功能系統
- 何時使用多租戶
- 第17章 構建自動化測試
- 了解ABP測試基礎設施
- 構建單元測試
- 構建集成測試