使用Angular2及WebApi开发SPA类型的企业应用 - Part 6- RESTful 和 WebApi

来源:互联网 发布:怎么把淘宝开通手机 编辑:程序博客网 时间:2024/06/08 02:43

使用Angular2及RESTful WebApi开发SPA类型的企业应用 - Part 6 RESTful 和 WebApi
作者:techcoaching,翻译:飘落寒冰
原文 有道
注:第一次翻译文章,有错译之处还请多多包涵,欢迎指出以便改进。

在本文中,我们将简单介绍本项目如何使用RESTful/WebApi
从Github上下载源码

该系列的全部文章

  1. 概览
  2. 添加新角色
  3. 项目结构
  4. 多语言
  5. 依赖注入和控制反转-为什么和为什么不?
  6. RESTful & WebApi
  7. 应用生命周期管理
  8. 应用构建与部署

简介

本项目中,我们是用angular2(typescript)处理客户端逻辑和请求服务器端处理业务逻辑(C#)。

客户端和服务器通过WebApi(RESTful的Web Servic)来通信

客户端请求

在组件中,我们调用了相关的服务

@Component({    selector: "roles",    templateUrl: "app/modules/security/permission/permissions.html",    directives: [Grid, PageActions, Page]})export class Permissions extends BasePage {    private router: Router;    public model: PermissionsModel;    constructor(router: Router) {        super();        let self: Permissions = this;        self.router = router;        self.model = new PermissionsModel(self.i18nHelper);        self.loadPermissions();        this.model.addPageAction(new PageAction("btnAddPer", "security.permissions.addPermissionAction", () => self.onAddNewPermissionClicked()));    }    private loadPermissions() {        let self: Permissions = this;        permissionService.getPermissions().then(function (items: Array<any>) {            self.model.importPermissions(items);        });    }}

permissionService实际上是通过IConnector(IConnect是angular中调用Http的接口)向服务器发送请求。

import configHelper from "../../../../common/helpers/configHelper";import {Promise} from "../../../../common/models/promise";import {IoCNames} from "../../../../common/enum";import {IConnector} from "../../../../common/connectors/iconnector";let permissionService = {    getPermissions: getPermissions};export default permissionService;function getPermissions(): Promise {    let connector: IConnector = window.ioc.resolve(IoCNames.IConnector);    let url = String.format("{0}permissions", configHelper.getAppConfig().api.baseUrl);    return connector.get(url);}

IConnector中,我们用了Http服务

export class RESTConnector implements IConnector {    private static http: Http;    private static eventManager: EventManager;    constructor() {        let http: Http = window.appState.getInjector().get(Http);        this.setHttp(http);    }    public get(url: string): Promise {        RESTConnector.eventManager.publish(LoadingIndicatorEvent.Show);        let def = PromiseFactory.create();        let headers = new JsonHeaders();        RESTConnector.http.get(url, { headers: headers })            .map((response: any) => response.json())            .subscribe(            (data: any) => this.handleResponse(def, data),            (exception: any) => this.handleException(def, exception)            );        return def;    }}

服务器端API

我们通过PermissionsController接收请求

namespace App.Api.Features.Security{    [RoutePrefix("api/permissions")]    public class PermissionsController : ApiController    {        [HttpGet]        [Route()]        public IResponseData<IList<PermissionAsKeyNamePair>> GetPermissions()        {            IResponseData<IList<PermissionAsKeyNamePair>> response = new ResponseData<IList<PermissionAsKeyNamePair>>();            try            {                IPermissionService permissionService = IoC.Container.Resolve<IPermissionService>();                IList<PermissionAsKeyNamePair> pers = permissionService.GetPermissions();                response.SetData(pers);            }            catch (ValidationException ex)            {                response.SetErrors(ex.Errors);                response.SetStatus(System.Net.HttpStatusCode.PreconditionFailed);            }            return response;        }    }}

如果我们需要在请求时向server端传递参数,这些参数必须是DTO对。

RESTful规定了每种操作使用特定的Http Verb (Get, Create, Update, Delete) 和请求路径。我们不介绍这些内容。

我只想澄清一些不同之处:

我们定义了两种累行errors/excetion,分别用来返回:基础错误和业务错误

  • Infrastructure Error

用来处理网络错误(找不到路径,超时,…), IIS配置错误configuration on IIS。这意味着业务逻辑部分尚未执行。

  • Business Error

用来处理客户端传递到服务器端用来处理业务逻辑的数据有错误。

例如:用户的用户名和密码不匹配。这种情况下,我们不能用通过HttpCode 500传递,客户端不明白服务器端发生了什么事情。

所有我们需要把此错误返回给客户端

IResponseData<IList<PermissionAsKeyNamePair>> response = new ResponseData<IList<PermissionAsKeyNamePair>>();try{}catch (ValidationException ex){    response.SetErrors(ex.Errors);    response.SetStatus(System.Net.HttpStatusCode.PreconditionFailed);}return response;

REST工具的输出:
image

我们可以发现,API返回了多个校验错误,我们可以在UI中将他们展示出来。这种方式比返回一个通用错误要更友好。
image

在相应的service中,我们校验的了请求中的参数,如果校验失败,我们将抛出如下异常:

private void ValidateUserLoginRequest(UserSignInRequest request){    ValidationException exception = new ValidationException();    if (request == null)    {        exception.Add(new ValidationError("common.invalidRequest"));    }    if (String.IsNullOrWhiteSpace(request.Email))    {        exception.Add(new ValidationError("registration.signin.validation.emailRequired"));    }    if (String.IsNullOrWhiteSpace(request.Pwd))    {        exception.Add(new ValidationError("registration.signin.validation.pwdRequired"));    }    IUserRepository userRepository = IoC.Container.Resolve<IUserRepository>();    User userProfile = userRepository.GetByEmail(request.Email);    if (userProfile == null || EncodeHelper.EncodePassword(request.Pwd) != userProfile.Password)    {        exception.Add(new ValidationError("registration.signin.validation.invalidEmailOrPwd"));    }    exception.ThrowIfError();}

总结

本例中,API成功返回了处理结果(HttpCode 200),但是收到的确是业务逻辑错误。

一些朋友认为这可能令人困惑。如果您有更好的解决方案,我很高兴与各位一起探讨。

授权

本文,以及所包含的源码,文件遵循CPOL协议

0 0
原创粉丝点击