ABP官方文档(三十)【动态WebApi层】

来源:互联网 发布:淘宝物流配送模式 编辑:程序博客网 时间:2024/05/22 12:46

5.2 ABP表现层 - 动态WebApi层

5.2.1 建立动态WebApi控制器

这是一篇关于ASP.NET Web API的文档。如果你对ASP.NET感兴趣,请阅读ASP.NET Core文档。

Abp框架能够通过应用层自动生成web api:

    public interface ITaskAppService : IApplicationService    {        GetTasksOutput GetTasks(GetTasksInput input);        void UpdateTask(UpdateTaskInput input);        void CreateTask(CreateTaskInput input);    }

并且,我们想要暴露这个服务作为Web API Controller给客户端。那么,Abp框架通过一行关键代码的配置就可以自动、动态的为应用层建立一个web api 控制器:

Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder.For<ITaskAppService>("tasksystem/task").Build();

这样就OK了!建好的webapi控制器 /api/services/tasksystem/task 所有的方法都能够在客户端调用。webapi控制器通常是在模块初始化的时候完成配置。

ITaskAppService 是应用层服务(application service)接口,我们通过封装让接口实现一个api控制器。ITaskAppService不仅限于在应用层服务使用,这仅仅是我们习惯和推荐的使用方法。
tasksystem/task 是api 控制器的命名空间。一般来说,应当最少定义一层的命名空间,如:公司名称/应用程序/命名空间/命名空间1/服务名称。api/services/ 是所有动态web api的前缀。所以api控制器的地址一般是这样滴:/api/services/tasksystem/taskGetTasks 方法的地址一般是这样的:/api/services/tasksystem/task/getTasks 。因为在传统的js中都是使用 驼峰式 命名方法,这里也不一样。

ForAll方法

在程序的应用服务层建立多个api控制器可能让人觉得比较枯燥,DynamicApiControllerBuilper提供了建立所有应用层服务的方法,如下所示:

Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder    .ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")    .Build();

ForAll方法是一个泛型接口,第一个参数是从给定接口中派生的集合,最后一个参数则是services命名空间的前缀。ForAll集合有ITaskAppService和 IpersonAppService接口。根据如上配置,服务层的路由是这样的:’/api/services/tasksystem/task‘和’/api/services/tasksystem/person‘。

服务命名约定:服务名+AppService(在本例中是person+AppService) 的后缀会自动删除,生成的webapi控制器名为“person”。同时,服务名称将采用峰驼命名法。如果你不喜欢这种约定,你也可以通过 WithServiceName 方法来自定义名称。如果你不想创建所有的应用服务层中的某些服务,可以使用where来过滤部分服务。

重写ForAll

我们可以在ForAll方法后面重写配置,如:

Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder    .ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")    .Build();Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder    .For<ITaskAppService>("tasksystem/task")    .ForMethod("CreateTask").DontCreateAction().Build();

在上面代码中,我们为指定的程序集里面的所有Application服务创建了动态WebAPI Controllers。然后为应用服务(ITaskAppService>重写配置忽略CreateTask方法。

ForMethods

当我们使用ForAll方法的时候,可以使用 ForMethods 方法来更好的调整服务的方法,如:

Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder    .ForAll<IApplicationService>(Assembly.GetExecutingAssembly(), "app")    .ForMethods(builder =>    {        if (builder.Method.IsDefined(typeof(MyIgnoreApiAttribute)))        {            builder.DontCreate = true;        }    })    .Build();

在这个示例中,我们使用了一个自定义特性 MyIgnoreApiAttribute 来检查所有的方法,如果动态WebAPI Controller的Action上有该特性,那么我们不会为该Action创建Web API。

Http 谓词

默认,所有方法的创建是: POST。为了能够使用动态Web API Action,客户端应该使用POST发送请求。我们可以改变这个行为以不同的方式。

WithVerb 方法

我们可以对某个方法使用 WithVerb,如下:

Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder    .For<ITaskAppService>("tasksystem/task")    .ForMethod("GetTasks").WithVerb(HttpVerb.Get)    .Build();
Http 特性

我们可以在服务接口的方法上使用HttpGet,HttpPost…等特性:

public interface ITaskAppService : IApplicationService{    [HttpGet]    GetTasksOutput GetTasks(GetTasksInput input);    [HttpPut]    void UpdateTask(UpdateTaskInput input);    [HttpPost]    void CreateTask(CreateTaskInput input);}

为了能使用这些特性,我们应该在项目中引用这个包:Microsoft.AspNet.WebApi.Core nuget package。

命名约定

我们可以使用 WithConventionalVerbs 方法来代替Http谓词,如下所示:

Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder    .ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")    .WithConventionalVerbs()    .Build();

在这种情况下,ABP可以通过方法名字的前缀来判定Http谓词:

  • Get:如果方法的名字是以 Get 开头

  • Put:如果方法的名字是以 Put 或者 Update 开头

  • Delete:如果方法的名字是以 Delete 或者 Remove 开头

  • Post:如果方法的名字是以 Post,Create 或者 Insert 开头

  • Path:如果方法的名字是以 Path 开头

  • 否则 Post 被作为Http谓词的默认设置

如前所述:我们可以覆盖某个特定的方法。

API Explorer

默认在API Explorer所有的动态WebApi控制器都是可见的(在Swagger中是有效的)。你可以使用 DynamicApiControllerBuilder API来控制这个默认行为,或者使用 RemoteService 特性来定义它。

RemoteService Attribute

你也可以在 接口上或者接口中的方法上 使用 RemoteService 特性来开启/禁用(IsEnabled)动态WebApi或者API Explorer设置(IsMetadataEnabled)。

5.2.2 使用动态JavaScript代理

你可以通过ajax来动态创建web api控制器。Abp框架对通过动态js代理建立web api 控制器做了些简化,你可以通过js来动态调用web api控制器:

abp.services.tasksystem.task.getTasks({    state: 1}).done(function (data) {//use data.tasks here..});

js代理是动态创建的,页面中需要添加引用:

<script src="/api/AbpServiceProxies/GetAll" type="text/javascript"></script>

服务方法返回约定(可参见jQuery.Deferred),你可以注册done,fail,then… 等回调方法。服务方法内部使用的是 abp.ajax,如果有需要的话可以使用它们处理错误和显示错误。

1. Ajax参数

自定义ajax代理方法的参数:

Abp.services.tasksystem.task.createTask({    assignedPersonId: 3,    description: 'a new task description...'},{ //override jQuery's ajax parameters    async: false,    timeout: 30000}).done(function () {    Abp.notify.success('successfully created a task!');});

所有的jq.ajax参数都是有效的。

除了标准的JQuery.ajax参数,为了禁用错误信息自动显示,你可以添加AJAX选项:abpHandleError: false

2. 单一服务脚本

‘/api/abpServiceProxies/GetAll’将在一个文件中生成所有的代理,通过 ‘/api/abpServiceProxies/Get?name=serviceName’ 你也可以生成单一服务代理,在页面中添加:

<script src="/api/abpServiceProxies/Get?name=tasksystem/task" type="text/javascript"></script>

3. Augular框架支持

Abp框架能够公开动态的api控制器作为angularjs服务,如下所示:

(function() {    angular.module('app').controller('TaskListController', [        '$scope', 'abp.services.tasksystem.task',        function($scope, taskService) {            var vm = this;            vm.tasks = [];            taskService.getTasks({                state: 0            }).success(function(data) {                vm.tasks = data.tasks;            });        }    ]);})();

我们可以将名称注入服务,然后调用此服务,跟调用一般的js函数一样。注意:我们成功注册处理程序后,他就像一个augular的httpABP使angularhttp服务,如果你想通过$http来配置,你可以设置一个配置对象作为服务方法的一个参数。

要使用自动生成的服务,需要在页面中添加:

<script src="~/Abp/Framework/scripts/libs/angularjs/abp.ng.js"></script><script src="~/api/AbpServiceProxies/GetAll?type=angular"></script>

Enable/Disable

如果你向上面一样使用 ForAll 方法,那么你可以使用 RemoteService 特性来禁用某个服务或方法。请在 服务的接口 中使用该特性,而不是在服务类中。

包装结果

ABP通过 AjaxResponse 对象来 包装 动态Web API Actions的返回值。你可以Enable/Disable包装对每个方法或应用服务。如下所示:

public interface ITestAppService : IApplicationService{    [DontWrapResult]    DoItOutput DoIt(DoItInput input);}

我们对DoIt禁用了包装。这个特性应该在添加在接口里面的方法描述上,而不是扩展类上。

如果你想更精确的控制返回值到客户端,禁用包装是非常有用的。特别是在使用第三方客户端库的时候,禁用包装是有必要的,因为ABP的标准包装 AjaxResponse 可能不能与之一起使用。在这种情况下,你也应该自己处理异常,因为异常处理会被禁用掉(DontWrapResult特性有个属性:WrapOnError,该属性可以被用来开启异常处理并对异常进行包装)。

注意:动态脚本代理能够使用该结果,如果该结果是未包装,而且且能够正常的被处理。

关于参数绑定

ABP在运行时创建API Controllers。所以ASP.NET Web API 的模型和参数绑定被使用来绑定模型和参数。你可以读取该文档获取更多信息。

FormUri 和 FormBody 特性

FromUri 和 FromBody 特性能够在服务接口中被使用增进对绑定的控制。

数据传输对象 VS 原生类型

对于应用服务和Web API控制器,我强烈建议使用DTO来作为方法参数。但是你也可以使用原生类型(如:string,int,bool …或可空类型,如:int?,bool? …) 作为服务方法的参数。可以使用多个参数;但是,在这些参数中有且只能有一个 Complex-Type 参数,这是ASP.NET Web API 规定的。