项目
版本

本文档有多个版本。请选择最适合您的选项。

UI
Database

Web应用程序开发教程 - 第二章: 图书列表页面

关于本教程

在本系列教程中, 你将构建一个名为 Acme.BookStore 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以下技术开发的:

  • MongoDB 做为ORM提供程序.
  • Blazor Server 做为UI框架.

本教程分为以下部分:

下载源码

本教程根据你的UI数据库偏好有多个版本,我们准备了几种可供下载的源码组合:

如果你在Windows中遇到 "文件名太长" or "解压错误", 很可能与Windows最大文件路径限制有关. Windows文件路径的最大长度为250字符. 为了解决这个问题,参阅 在Windows 10中启用长路径.

如果你遇到与Git相关的长路径错误, 尝试使用下面的命令在Windows中启用长路径. 参阅 https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path git config --system core.longpaths true

本地化

开始的UI开发之前,我们首先要准备本地化的文本(这是你通常在开发应用程序时需要做的).

本地化文本位于 Acme.BookStore.Domain.Shared 项目的 Localization/BookStore 文件夹下:

bookstore-localization-files

打开 en.json (英文翻译)文件并更改内容,如下所示:

{
  "Culture": "en",
  "Texts": {
    "Menu:Home": "Home",
    "Welcome": "Welcome",
    "LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
    "Menu:BookStore": "Book Store",
    "Menu:Books": "Books",
    "Actions": "Actions",
    "Close": "Close",
    "Delete": "Delete",
    "Edit": "Edit",
    "PublishDate": "Publish date",
    "NewBook": "New book",
    "Name": "Name",
    "Type": "Type",
    "Price": "Price",
    "CreationTime": "Creation time",
    "AreYouSure": "Are you sure?",
    "AreYouSureToDelete": "Are you sure you want to delete this item?",
    "Enum:BookType.Undefined": "Undefined",
    "Enum:BookType.Adventure": "Adventure",
    "Enum:BookType.Biography": "Biography",
    "Enum:BookType.Dystopia": "Dystopia",
    "Enum:BookType.Fantastic": "Fantastic",
    "Enum:BookType.Horror": "Horror",
    "Enum:BookType.Science": "Science",
    "Enum:BookType.ScienceFiction": "Science fiction",
    "Enum:BookType.Poetry": "Poetry"
  }
}

简体中文翻译请打开zh-Hans.json文件 ,并将"Texts"对象中对应的值替换为中文.

  • 本地化关键字名称是任意的. 你可以设置任何名称. 对于特定的文本类型,我们更喜欢遵循一些约定:
    • 为按钮项添加 Menu: 前缀.
    • 使用 Enum:<enum-type>:<enum-name><enum-type>.<enum-name><enum-name> 命名约定来本地化枚举成员. 当您这样做时ABP可以在某些适当的情况下自动将枚举本地化.

如果未在本地化文件中定义文本,则文本将回退到本地化键(ASP.NET Core的标准行为).

ABP本地化系统建立在ASP.NET Core标准本地化系统之上,并以多种方式进行了扩展. 有关详细信息请参见本地化文档.

创建图书页面

是时候创建可见和可用的东西了! 右击Acme.BookStore.Blazor项目下的Pages文件夹,新建一个名为Books.razorrazor组件.

blazor-add-books-component

用以下内容替换这个组件的内容:

@page "/books"

<h2>Books</h2>

@code {

}

将图书页面添加到主菜单

打开Blazor项目中的BookStoreMenuContributor类,在 ConfigureMainMenuAsync 方法的底部添加如下代码:

context.Menu.AddItem(
    new ApplicationMenuItem(
        "BooksStore",
        l["Menu:BookStore"],
        icon: "fa fa-book"
    ).AddItem(
        new ApplicationMenuItem(
            "BooksStore.Books",
            l["Menu:Books"],
            url: "/books"
        )
    )
);

运行项目,使用用户名 admin 和密码 1q2w3E* 登录到应用程序. 看到新菜单项已添加到顶部栏:

blazor-menu-bookstore

点击BookStore下的Books子菜单项就会跳转到空的图书页面.

图书列表

我们将使用Blazorise library作为UI组件.它是一个强大的库,支持主要的HTML/CSS框架,包括Bootstrap.

ABP提供了一个通用的基类,AbpCrudPageBase<...>,用来创建CRUD风格的页面.这个基类兼容用来构建IBookAppServiceICrudAppService.所以我们从AbpCrudPageBase继承,获得标准CRUD的默认实现.

打开Books.razor 并把内容修改成下面这样:

@page "/books"
@using Volo.Abp.Application.Dtos
@using Acme.BookStore.Books
@using Acme.BookStore.Localization
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<BookStoreResource> L
@inherits AbpCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>

<Card>
    <CardHeader>
        <h2>@L["Books"]</h2>
    </CardHeader>
    <CardBody>
        <DataGrid TItem="BookDto"
                  Data="Entities"
                  ReadData="OnDataGridReadAsync"
                  TotalItems="TotalCount"
                  ShowPager="true"
                  PageSize="PageSize">
            <DataGridColumns>
                <DataGridColumn TItem="BookDto"
                                Field="@nameof(BookDto.Name)"
                                Caption="@L["Name"]"></DataGridColumn>
                <DataGridColumn TItem="BookDto"
                                Field="@nameof(BookDto.Type)"
                                Caption="@L["Type"]">
                    <DisplayTemplate>
                        @L[$"Enum:BookType.{Enum.GetName(context.Type)}"]
                    </DisplayTemplate>
                </DataGridColumn>
                <DataGridColumn TItem="BookDto"
                                Field="@nameof(BookDto.PublishDate)"
                                Caption="@L["PublishDate"]">
                    <DisplayTemplate>
                        @context.PublishDate.ToShortDateString()
                    </DisplayTemplate>
                </DataGridColumn>
                <DataGridColumn TItem="BookDto"
                                Field="@nameof(BookDto.Price)"
                                Caption="@L["Price"]">
                </DataGridColumn>
                <DataGridColumn TItem="BookDto"
                                Field="@nameof(BookDto.CreationTime)"
                                Caption="@L["CreationTime"]">
                    <DisplayTemplate>
                        @context.CreationTime.ToLongDateString()
                    </DisplayTemplate>
                </DataGridColumn>
            </DataGridColumns>
        </DataGrid>
    </CardBody>
</Card>

如果你可以编译并运行成功,但看到一些语法错误.你可以忽略这些错误,因为Visual Studio处理Blazor还有一些bug.

  • AbpCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>实现了所有的CRUD细节,我们从它继承.
  • Entities, TotalCount, PageSize, OnDataGridReadAsync定义在基类中.
  • 注入IStringLocalizer<BookStoreResource> (作为L对象),用于本地化.

虽然上面的代码非常容易理解,你仍然可以查看Blazorise CardDataGrid文档以更好地理解它们.

关于AbpCrudPageBase

对于图书页面,我们将持续从AbpCrudPageBase获得益处. 你可以只注入IBookAppService并自己执行所有的服务端调用(感谢ABP的动态C# HTTP API客户端代理系统).

运行最终应用程序

你可以运行应用程序!该部分的最终用户界面如下所示:

blazor-bookstore-book-list

这是一个可以正常工作的,服务端分页,排序和本地化的图书列表.

下一章

查看本教程的下一章.

在本文档中