- 关于本教程
- 下载源代码
- 介绍
- 图书列表页面
- Index.cshtml
- IndexModel.cshtml.cs
- Index.js
- 本地化
- 添加到主菜单
- 运行应用程序
- 创建模态
- CreateModal.cshtml
- CreateModal.cshtml.cs
- 编辑模态
- EditModal.cshtml
- EditModal.cshtml.cs
- 下一部分
本教程基于版本3.1
在本教程系列中,您将构建一个名为Acme.BookStore
的基于ABP的Web应用程序。该应用程序用于管理书籍及其作者的列表。它是使用以下技术开发的:
- 实体框架核心作为ORM提供者。
- MVC/Razor页面作为UI框架。
本教程分为以下部分:
第1部分:创建服务器端
第2部分:书籍列表页面
第3部分:创建、更新和删除书籍
第4部分:集成测试
第5部分:授权
第6部分:作者:领域层
第7部分:作者:数据库集成
第8部分:作者:应用程序层
第9部分:作者:用户界面(此部分)
第10部分:书与作者的关系
下载源代码MVC (Razor Pages) UI with EF Core
介绍本部分说明了如何为前面部分介绍的Author
实体创建CRUD页面。
在Acme.BookStore.Web
项目Pages/Authors
文件夹下创建一个新的Index.cshtml
razor页面,并按如下所示更改内容。
@page
@using Acme.BookStore.Localization
@using Acme.BookStore.Permissions
@using Acme.BookStore.Web.Pages.Authors
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Extensions.Localization
@inject IStringLocalizer L
@inject IAuthorizationService AuthorizationService
@model IndexModel
@section scripts
{
}
@L["Authors"]
@if (await AuthorizationService
.IsGrantedAsync(BookStorePermissions.Authors.Create))
{
}
这是一个简单的页面,类似于我们之前创建的“图书(Books)”页面。它将导入一个JavaScript文件,下面将对其进行介绍。
IndexModel.cshtml.csusing Microsoft.AspNetCore.Mvc.RazorPages;
namespace Acme.BookStore.Web.Pages.Authors
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
Index.js
$(function () {
var l = abp.localization.getResource('BookStore');
var createModal = new abp.ModalManager(abp.appPath + 'Authors/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'Authors/EditModal');
var dataTable = $('#AuthorsTable').DataTable(
abp.libs.datatables.normalizeConfiguration({
serverSide: true,
paging: true,
order: [[1, "asc"]],
searching: false,
scrollX: true,
ajax: abp.libs.datatables.createAjax(acme.bookStore.authors.author.getList),
columnDefs: [
{
title: l('Actions'),
rowAction: {
items:
[
{
text: l('Edit'),
visible:
abp.auth.isGranted('BookStore.Authors.Edit'),
action: function (data) {
editModal.open({ id: data.record.id });
}
},
{
text: l('Delete'),
visible:
abp.auth.isGranted('BookStore.Authors.Delete'),
confirmMessage: function (data) {
return l(
'AuthorDeletionConfirmationMessage',
data.record.name
);
},
action: function (data) {
acme.bookStore.authors.author
.delete(data.record.id)
.then(function() {
abp.notify.info(
l('SuccessfullyDeleted')
);
dataTable.ajax.reload();
});
}
}
]
}
},
{
title: l('Name'),
data: "name"
},
{
title: l('BirthDate'),
data: "birthDate",
render: function (data) {
return luxon
.DateTime
.fromISO(data, {
locale: abp.localization.currentCulture.name
}).toLocaleString();
}
}
]
})
);
createModal.onResult(function () {
dataTable.ajax.reload();
});
editModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewAuthorButton').click(function (e) {
e.preventDefault();
createModal.open();
});
});
简而言之,这个JavaScript页面;
- 创建一个带有
Actions
,Name
和BirthDate
列的数据表。Actions
列用于添加编辑和删除操作。BirthDate
提供了一个render
函数来使用luxon库格式化DateTime
值。
- 使用
abp.ModalManager
打开创建和编辑模态表单。
此代码与之前创建的“图书(Books)”页面非常相似,因此我们将不再对其进行详细说明。
本地化该页面使用了一些我们需要声明的本地化关键字。打开Acme.BookStore.Domain.Shared
项目Localization/BookStore
文件夹下的en.json
文件,并添加以下条目:
"Menu:Authors": "Authors",
"Authors": "Authors",
"AuthorDeletionConfirmationMessage": "Are you sure to delete the author '{0}'?",
"BirthDate": "Birth date",
"NewAuthor": "New author"
注意,我们添加了更多键。它们将在下一节中使用。
添加到主菜单在Acme.BookStore.Web
项目的Menus
文件夹中打开BookStoreMenuContributor.cs
,然后在ConfigureMainMenuAsync
方法末尾添加以下代码:
if (await context.IsGrantedAsync(BookStorePermissions.Authors.Default))
{
bookStoreMenu.AddItem(new ApplicationMenuItem(
"BooksStore.Authors",
l["Menu:Authors"],
url: "/Authors"
));
}
运行应用程序
运行并登录到该应用程序。您尚未获得权限,因此无法看到菜单项。转到Identity/Roles
页面,单击“操作(Actions)”按钮,然后为管理员角色选择权限操作:
如您所见,管理员角色还没有作者管理权限。单击复选框,然后保存模态以授予必要的权限。刷新页面后,您将在主菜单中的“书店(Book Store)”下看到“作者(Authors)”菜单项:
除“新作者(New author)”和“操作/编辑(Actions/Edit)”外,该页面可以正常使用,因为我们尚未实现它们。
提示:如果在定义新权限后运行.DbMigrator
控制台应用程序,它将自动将这些新权限授予管理员角色,并且您无需自己手动授予权限。
在Acme.BookStore.Web
项目Pages/Authors
文件夹下创建一个新的CreateModal.cshtml
razor页面,并按如下所示更改内容。
@page
@using Acme.BookStore.Localization
@using Acme.BookStore.Web.Pages.Authors
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model CreateModalModel
@inject IStringLocalizer L
@{
Layout = null;
}
之前,我们在书籍页面上使用了ABP框架的动态表单。我们可以在此处使用相同的方法,但我们想展示如何手动进行。实际上,不是手动操作,因为在这种情况下,我们使用了abp-input
标签帮助程序来简化表单元素的创建。
您绝对可以使用标准的Bootstrap HTML结构,但这需要编写大量代码。根据数据类型abp-input
自动添加验证,本地化和其他标准元素。
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Acme.BookStore.Authors;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Acme.BookStore.Web.Pages.Authors
{
public class CreateModalModel : BookStorePageModel
{
[BindProperty]
public CreateAuthorViewModel Author { get; set; }
private readonly IAuthorAppService _authorAppService;
public CreateModalModel(IAuthorAppService authorAppService)
{
_authorAppService = authorAppService;
}
public void OnGet()
{
Author = new CreateAuthorViewModel();
}
public async Task OnPostAsync()
{
var dto = ObjectMapper.Map(Author);
await _authorAppService.CreateAsync(dto);
return NoContent();
}
public class CreateAuthorViewModel
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[TextArea]
public string ShortBio { get; set; }
}
}
}
此页面模型类仅注入并使用IAuthorAppService
来创建新作者。书籍创建模型类之间的主要区别在于,该类为CreateAuthorViewModel
视图模型声明了一个新类,而不是重用CreateAuthorDto
。
做出此决定的主要原因是向您展示如何在页面内使用其他模型类。但是还有另一个好处:我们为类成员添加了两个属性,它们在CreateAuthorDto
中没有:
-
向
BirthDate
添加了[DataType(DataType.Date)]
属性,该属性在UI上显示了此属性的日期选择器。 -
向
ShortBio
添加了[TextArea]
属性,该属性显示多行文本区域而不是标准文本框。
这样,您可以根据UI需求专门化视图模型类,而不涉及DTO。由于此决定,我们使用ObjectMapper
映射CreateAuthorViewModel
到CreateAuthorDto
。为此,您需要向BookStoreWebAutoMapperProfile
构造函数添加新的映射代码:
using Acme.BookStore.Authors; // ADDED NAMESPACE IMPORT
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore.Web
{
public class BookStoreWebAutoMapperProfile : Profile
{
public BookStoreWebAutoMapperProfile()
{
CreateMap();
// ADD a NEW MAPPING
CreateMap();
}
}
}
当您再次运行该应用程序时,“新作者(New author)”按钮将按预期工作并打开一个新模型:
在Acme.BookStore.Web
项目Pages/Authors
文件夹下创建一个新的EditModal.cshtml
razor页面,并按如下所示更改内容。
@page
@using Acme.BookStore.Localization
@using Acme.BookStore.Web.Pages.Authors
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model EditModalModel
@inject IStringLocalizer L
@{
Layout = null;
}
EditModal.cshtml.cs
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Acme.BookStore.Authors;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Acme.BookStore.Web.Pages.Authors
{
public class EditModalModel : BookStorePageModel
{
[BindProperty]
public EditAuthorViewModel Author { get; set; }
private readonly IAuthorAppService _authorAppService;
public EditModalModel(IAuthorAppService authorAppService)
{
_authorAppService = authorAppService;
}
public async Task OnGetAsync(Guid id)
{
var authorDto = await _authorAppService.GetAsync(id);
Author = ObjectMapper.Map(authorDto);
}
public async Task OnPostAsync()
{
await _authorAppService.UpdateAsync(
Author.Id,
ObjectMapper.Map(Author)
);
return NoContent();
}
public class EditAuthorViewModel
{
[HiddenInput]
public Guid Id { get; set; }
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[TextArea]
public string ShortBio { get; set; }
}
}
}
此类类似于CreateModal.cshtml.cs
,但有一些主要区别。
-
使用
IAuthorAppService.GetAsync(...)
方法从应用程序层获取编辑作者。 -
EditAuthorViewModel
有一个附加Id
属性,它被标记为[HiddenInput]
属性,该属性为该属性创建一个隐藏的输入。
该类需要向该类添加两个对象映射声明BookStoreWebAutoMapperProfile:
using Acme.BookStore.Authors;
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore.Web
{
public class BookStoreWebAutoMapperProfile : Profile
{
public BookStoreWebAutoMapperProfile()
{
CreateMap();
CreateMap();
// ADD THESE NEW MAPPINGS
CreateMap();
CreateMap();
}
}
}
就这样!您可以运行该应用程序并尝试编辑作者。
下一部分请参阅本教程的下一部分。