XHTMLADO.NET设计/图形LINQ架构师CSSXMLAjaxMVC初学者jQueryHTML中级开发Visual StudioSQL ServerJavascript.NETASP.NETC#
单页应用程序(SPA)用于企业应用程序(Angular2 & WebApi)- 第 2 部分 - 添加新权限






4.85/5 (23投票s)
在本文中,我们将学习如何创建/编辑角色
系列中的其他文章
- 概述
- 项目结构
- 多语言 (i18n)
- DI & IoC - 为什么以及为什么不?
- RESTful & WebApi
- 管理应用生命周期
- 构建和部署应用
- TinyERP新版本(使用Angular 2 (typescript))
- CQRS:避免企业应用中的性能问题(第一部分)
- 多个数据存储:扩展你的存储库(第1部分)
- 多个数据存储:扩展你的存储库(第2部分)
- 基本身份验证(用户名/密码)与OWIN
引言
我首先想与您分享的是“我们不学习技术,我们学习如何为我们的业务使用技术”。
注意:在此代码中,我们使用了 Angular 2 的 Release Candidate 版本
在本部分中,我们将通过一系列步骤了解如何使用我的代码来实现“添加角色”页面,如下图所示
如何获取代码
请查看代码:https://github.com/techcoaching/TinyERP.git。
分析页面
习惯上,在实现之前我会先分析页面,这将帮助我们
- 列出完成页面所需的步骤。
- 找出缺失的信息,以便我们立即寻求帮助。
- 思考从客户端到服务器端,从 UI 到存储库的逻辑流程。这样编写的代码会更漂亮。为此,我的许多同事会先编写代码,然后再调试。当出现问题时,它会改变我们的行为,我们试图更改代码使其正常工作。这可能会破坏逻辑流程,并且代码不符合约定。应用程序中使用的架构。这将在未来引发一些新的潜在问题,并且代码难以维护。
分析页面后,我们找出需要完成的项目列表如下:
客户端
- 注册“添加角色”页面的路由(Angular 2 中的组件)
- 创建组件文件(HTML 文件用于 UI,ts 文件用于逻辑处理,ts 文件用于该组件的视图模型)。
- 实现“添加角色”组件的 UI
- 实现“添加角色”组件的逻辑。
- 为该页面实现服务(服务将调用 REST API 在服务器上创建/更新数据)。
API
- 在
RolesController
中添加新方法以处理与Role
相关的创建请求 - 在
Role
服务和Role
存储库中添加新方法以创建Role
实现客户端
在本节中,<root>文件夹是客户端代码的文件夹(路径为“client”文件夹)。
- 注册“添加角色”页面的路由(Angular 2 中的组件)
转到“<root>/app/modules/secutiry/_share/config”并更新
addRoutes
方法import {IModule, Module, MenuItem} from "../../../../common/models/layout"; import {Roles} from "../../role/roles"; import {AddRole} from "../../role/addRole"; import {AuthenticationMode} from "../../../../common/enum"; import route from "./route"; let module: IModule = createModule(); export default module; function createModule() { let module = new Module("app/modules/secutiry", "secutiry"); module.menus.push( new MenuItem( "Security", route.role.roles.name, "fa fa-user-md", new MenuItem("Roles", route.role.roles.name, ""), ) ); module.addRoutes([ { path: route.role.roles.path, name: route.role.roles.name, component: Roles, data: { authentication: AuthenticationMode.Require }, useAsDefault: true }, { path: route.role.addRole.path, name: route.role.addRole.name, component: AddRole, data: { authentication: AuthenticationMode.Require } } ]); return module; }
route.ts的内容将是
let route = { role: { roles: { name: "Roles", path: "/roles" }, addRole: { name: "Add Role", path: "/addRole" } } }; export default route;
- 创建组件文件(HTML 文件用于 UI,ts 文件用于逻辑处理,ts 文件用于该组件的视图模型)。
- 实现“添加或编辑角色”组件的 UI
<page> <page-header> {{i18n.security.addOrUpdateRole.title}} </page-header> <page-content> <form-default> <form-text-input [placeHolderText]=i18n.security.addOrUpdateRole.inputName [labelText]=i18n.security.addOrUpdateRole.name [validation]="['security.addOrUpdateRole.validation.nameIsRequire', 'security.addOrUpdateRole.validation.keyAlreadyExisted']" [(model)]=model.name> </form-text-input> <form-textarea [placeHolderText]=i18n.security.addOrUpdateRole.inputDesc [labelText]=i18n.security.addOrUpdateRole.desc [(model)]=model.description> </form-textarea> <form-permission-select [(values)]=model.permissions [placeHolderText]=i18n.security.addOrUpdateRole.inputPermissions [labelText]=i18n.security.addOrUpdateRole.permission [(model)]=model.permissions> </form-permission-select> <form-footer> <button id="save" (click)="onSaveClicked($event)" type="button" class="btn btn-primary">{{i18n.common.form.save}}</button> <button id="cancel" (click)="onCancelClicked($event)" type="button" class="btn btn-default">{{i18n.common.form.cancel}}</button> </form-footer> </form-default> </page-content> </page>
输出到浏览器的效果如下图所示
在此文件中
- 我们没有使用传统的 HTML 来创建表单的 UI,有许多指令可用于此目的,例如:
form
、form-textarea
等。 - 页面结构如下:
page-header
:包含页面的标题文本page-content
:这是页面的主要内容区域
- 我们没有使用传统的 HTML 来创建表单的 UI,有许多指令可用于此目的,例如:
- 实现“添加角色”组件的逻辑。
import {BasePage} from "../../../common/models/ui"; import {Router, RouteParams} from "angular2/router"; import {Component} from "angular2/core"; import {AddRoleModel} from "./addRoleModel"; import {Page, SelectPermission, Form, FormTextInput, FormFooter, FormTextArea, FormPermissionSelect} from "../../../common/directive"; import {ValidationDirective} from "../../../common/directive"; import roleService from "../_share/services/roleService"; import {FormMode} from "../../../common/enum"; import route from "../_share/config/route"; @Component({ templateUrl: "app/modules/security/role/addRole.html", directives: [Page, Form, FormTextInput, FormFooter, FormTextArea, FormPermissionSelect] }) export class AddRole extends BasePage { public model: AddRoleModel = new AddRoleModel(); private router: Router; constructor(router: Router, routeParams: RouteParams) { super(); let self: AddRole = this; self.router = router; } public onSaveClicked(event: any): void { let self: AddRole = this; roleService.create(this.model).then(function () { self.router.navigate([route.role.roles.name]); }); } public onCancelClicked(event: any): void { let self: AddRole = this; self.router.navigate([route.role.roles.name]); } }
在此文件中,我们
- 通过
routeParams.get("id")
获取选定角色的 ID - 使用
router.navigate
方法在页面之间导航
- 通过
- 为该页面实现服务(服务将调用 REST API 在服务器上创建数据)。
import configHelper from "../../../../common/helpers/configHelper"; import {Promise} from "../../../../common/models/promise"; let roleServices = { getRoles: getRoles, create: create }; export default roleServices; function getRoles(): Promise { let connector = window.ioc.resolve("IConnector"); let url = String.format("{0}roles", configHelper.getAppConfig().api.baseUrl); return connector.get(url); } function create(role: any): Promise { let connector = window.ioc.resolve("IConnector"); let url = String.format("{0}roles", configHelper.getAppConfig().api.baseUrl); return connector.post(url, role); }
实现 API
- 在
RolesController
中添加新方法以处理与Role
相关的创建请求。using App.Common.DI; using App.Common.Http; using App.Common.Validation; using App.Service.Security; using System; using System.Collections.Generic; using System.Web.Http; namespace App.Api.Features.Security { [RoutePrefix("api/roles")] public class RolesController : ApiController { [HttpGet] [Route("")] public IResponseData<IList<RoleListItemSummary>> GetRoles() { IResponseData<IList<RoleListItemSummary>> response = new ResponseData<IList<RoleListItemSummary>>(); try { IRoleService roleService = IoC.Container.Resolve<IRoleService>(); IList<RoleListItemSummary> roles=roleService.GetRoles(); response.SetData(roles); } catch (ValidationException ex) { response.SetErrors(ex.Errors); response.SetStatus(System.Net.HttpStatusCode.PreconditionFailed); } return response; } [HttpPost] [Route("")] public IResponseData<CreateRoleResponse> CreateRole(CreateRoleRequest request) { IResponseData<CreateRoleResponse> response = new ResponseData<CreateRoleResponse>(); try { IRoleService roleService = IoC.Container.Resolve<IRoleService>(); CreateRoleResponse role = roleService.Create(request); response.SetData(role); } catch (ValidationException ex) { response.SetErrors(ex.Errors); response.SetStatus(System.Net.HttpStatusCode.PreconditionFailed); } return response; } } }
- 在
IRoleService
和RoleService
中添加新方法以创建Role
。- IRoleService.cs
namespace App.Service.Security { public interface IRoleService { System.Collections.Generic.IList<RoleListItemSummary> GetRoles(); CreateRoleResponse Create(CreateRoleRequest request); } }
- RoleService.cs
using System.Collections.Generic; using App.Service.Security; using App.Common.DI; using App.Repository.Secutiry; using App.Entity.Security; using App.Common; namespace App.Service.Impl.Security { public class RoleService : IRoleService { public CreateRoleResponse Create(CreateRoleRequest request) { ValidateCreateRequest(request); using (App.Common.Data.IUnitOfWork uow = new App.Common.Data.UnitOfWork(new App.Context.AppDbContext(IOMode.Write))) { IRoleRepository roleRepository = IoC.Container.Resolve<IRoleRepository>(uow); IPermissionRepository permissionRepo = IoC.Container.Resolve<IPermissionRepository>(uow); IList<Permission> permissions = permissionRepo.GetPermissions(request.Permissions); Role role = new Role(request.Name, request.Description, permissions); roleRepository.Add(role); uow.Commit(); } return new CreateRoleResponse(); } private void ValidateCreateRequest(CreateRoleRequest request) { if (string.IsNullOrWhiteSpace(request.Name)) { throw new App.Common.Validation.ValidationException ("security.addOrUpdateRole.validation.nameIsRequire"); } } public IList<RoleListItemSummary> GetRoles() { IRoleRepository repository = IoC.Container.Resolve<IRoleRepository>(); return repository.GetItems<RoleListItemSummary>(); } } }
在
Role
服务中- 用户调用
Role
存储库的Create
方法来创建新的Role
。 - 在
UnitOfWork
中,我们明确指定了我们要为该UnitOfWork
使用的模式。这可以防止意外的更改被保存到数据库。 - “
security.addOrUpdateRole.validation.nameIsRequire
”,它将在客户端根据当前语言解析,并将错误显示为每个表单组件上的工具提示。在我的代码中,服务应该只向客户端返回错误的键,客户端将自行以适当的语言显示。
IRoleRepository
和RoleRepository
用于创建Role
。我们不需要更改此存储库,因为它从
IBaseContentRepository
和BaseContentRepository
继承了相应的方法。namespace App.Repository.Secutiry { public interface IRoleRepository: App.Common.Data.IBaseContentRepository<Role> { } } using App.Common.Data.MSSQL; using App.Entity.Security; using App.Repository.Secutiry; namespace App.Repository.Impl.Security { public class RoleRepository: BaseContentRepository<Role>, IRoleRepository { public RoleRepository() : base(new App.Context.AppDbContext(App.Common.IOMode.Read)) { } public RoleRepository(IUnitOfWork uow) : base(uow.Context as IMSSQLDbContext) { } } }
有关 Angular 2 的更多信息,请参阅“Angular 2 - Overview”。
摘要
到目前为止,我们可以使用代码创建新的Role
。
有关更多信息
- Angular2,请访问
- 有关Angular的概述,请访问 https://codeproject.org.cn/Articles/1164843/Angular-Overview
- 有关Angular中的路由,请访问 https://codeproject.org.cn/Articles/1164813/Angular-Routing
- 有关Angular中的组件,请访问 https://codeproject.org.cn/Articles/1166112/Angular-Component
- 有关Angular中的绑定,请访问 https://codeproject.org.cn/Articles/1166418/Angular-Binding
- 有关Angular中的指令,请访问
- 将“Angular 2”功能添加到当前的“Angular 1”应用程序中
- REST
- 有关概述概念,请访问 https://codeproject.org.cn/Articles/1164842/REST-Overview
- 有关在WebApi (C#) 中使用REST,请访问 https://codeproject.org.cn/Articles/1168872/REST-in-WebApi