65.9K
CodeProject 正在变化。 阅读更多。
Home

单页应用程序(SPA)用于企业应用程序(Angular2 & WebApi)- 第 2 部分 - 添加新权限

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (23投票s)

2017年3月21日

CPOL

4分钟阅读

viewsIcon

71018

在本文中,我们将学习如何创建/编辑角色

系列中的其他文章

  1. 概述
  2. 项目结构
  3. 多语言 (i18n)
  4. DI & IoC - 为什么以及为什么不?
  5. RESTful & WebApi
  6. 管理应用生命周期
  7. 构建和部署应用
  8. TinyERP新版本(使用Angular 2 (typescript))
  9. CQRS:避免企业应用中的性能问题(第一部分)
  10. 多个数据存储:扩展你的存储库(第1部分)
  11. 多个数据存储:扩展你的存储库(第2部分)
  12. 基本身份验证(用户名/密码)与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”文件夹)。

  1. 注册“添加角色”页面的路由(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;
  2. 创建组件文件(HTML 文件用于 UI,ts 文件用于逻辑处理,ts 文件用于该组件的视图模型)。

  3. 实现“添加或编辑角色”组件的 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,有许多指令可用于此目的,例如:formform-textarea等。
    • 页面结构如下:
      • page-header:包含页面的标题文本
      • page-content:这是页面的主要内容区域
  4. 实现“添加角色”组件的逻辑。
    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方法在页面之间导航
  5. 为该页面实现服务(服务将调用 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

  1. 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;
            }
        }
    }
  2. IRoleServiceRoleService中添加新方法以创建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”,它将在客户端根据当前语言解析,并将错误显示为每个表单组件上的工具提示。在我的代码中,服务应该只向客户端返回错误的键,客户端将自行以适当的语言显示。
  3. IRoleRepositoryRoleRepository用于创建Role

    我们不需要更改此存储库,因为它从IBaseContentRepositoryBaseContentRepository继承了相应的方法。

    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

有关更多信息

© . All rights reserved.