## 5.2 ABP表现层 - 动态WebApi层
### 5.2.1 建立动态WebApi控制器
> 这是一篇关于ASP.NET Web API的文档。如果你对ASP.NET感兴趣,请阅读[ASP.NET Core](225864)文档。
Abp框架能够通过应用层自动生成web api:
``` csharp
public interface ITaskAppService : IApplicationService
{
GetTasksOutput GetTasks(GetTasksInput input);
void UpdateTask(UpdateTaskInput input);
void CreateTask(CreateTaskInput input);
}
```
并且,我们想要暴露这个服务作为Web API Controller给客户端。那么,Abp框架通过一行关键代码的配置就可以自动、动态的为应用层建立一个web api 控制器:
```csharp
DynamicApiControllerBuilder.For<ITaskAppService>("tasksystem/task").Build();
```
这样就OK了!建好的webapi控制器(/api/services/tasksystem/task)所有的方法都能够在客户端调用。webapi控制器通常是在[模块初始化](225823)的时候完成配置。
ITaskAppService是应用层服务(application service)接口,我们通过封装让接口实现一个api控制器。ITaskAppService不仅限于在应用层服务使用,这仅仅是我们习惯和推荐的使用方法。
tasksystem/task是api 控制器的命名空间。一般来说,应当最少定义一层的命名空间,如:公司名称/应用程序/命名空间/命名空间1/服务名称。
‘api/services/’是所有动态web api的前缀。所以api控制器的地址一般是这样滴:‘/api/services/tasksystem/task’,GetTasks 方法的地址一般是这样滴:
‘/api/services/tasksystem/task/getTasks’。因为在传统的js中都是使用驼峰式命名方法,这里也不一样。
你也可以删除一个api方法,如下:
```csharp
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/taskService")
.ForMethod("CreateTask").DontCreateAction()
.Build();
```
#### ForAll方法
在程序的应用服务层建立多个api控制器可能让人觉得比较枯燥,DynamicApiControllerBuilper提供了建立所有应用层服务的方法,如下所示:
```csharp
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方法后面重写配置,如:
```csharp
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/task")
.ForMethod("CreateTask").DontCreateAction().Build();
```
在上面代码中,我们为指定的程序集里面的所有Application服务创建了动态WebAPI Controllers。然后为应用服务(ITaskAppService>重写配置忽略CreateTask方法。
#### ForMethods
当我们使用ForAll方法的时候,可以使用 **ForMethods** 方法来更好的调整服务的方法,如:
```csharp
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**,如下:
```csharp
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/task")
.ForMethod("GetTasks").WithVerb(HttpVerb.Get)
.Build();
```
##### Http 特性
我们可以在服务接口的方法上使用HttpGet,HttpPost...等特性:
```csharp
public interface ITaskAppService : IApplicationService
{
[HttpGet]
GetTasksOutput GetTasks(GetTasksInput input);
[HttpPut]
void UpdateTask(UpdateTaskInput input);
[HttpPost]
void CreateTask(CreateTaskInput input);
}
```
为了能使用这些特性,我们应该在项目中引用这个包:[Microsoft.AspNet.WebApi.Core](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Core) nuget package。
##### 命名约定
我们可以使用 **WithConventionalVerbs** 方法来代替Http谓词,如下所示:
```csharp
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谓词的默认设置
### 5.2.2 使用动态JavaScript代理
你可以通过ajax来动态创建web api控制器。Abp框架对通过动态js代理建立web api 控制器做了些简化,你可以通过js来动态调用web api控制器:
```javascript
abp.services.tasksystem.task.getTasks({
state: 1
}).done(function (data) {
//use data.tasks here..
});
```
js代理是动态创建的,页面中需要添加引用:
```html
<script src="/api/abp.ServiceProxies/GetAll" type="text/javascript"></script>
```
服务方法(service methods)返回约定(可参见JQ的Deferred),服务方法使用Abp框架.ajax代替,可以处理、显示错误。
#### 1. Ajax参数
自定义ajax代理方法的参数:
```javascript
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' 你也可以生成单一服务代理,在页面中添加:
```html
<script src="/api/abpServiceProxies/Get?name=tasksystem/task" type="text/javascript"></script>
```
#### 3. Augular框架支持
Abp框架能够公开动态的api控制器作为angularjs服务,如下所示:
```javascript
(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的$http服务。ABP框架使用angular框架的$http服务,如果你想通过$http来配置,你可以设置一个配置对象作为服务方法的一个参数。
要使用自动生成的服务,需要在页面中添加:
```html
<script src="~/abp Framework/Framework/scripts/libs/angularjs/Abp Framework.ng.js"></script>
<script src="~/api/abp Framework/ServiceProxies/GetAll?type=angular"></script>
```
#### Enable/Disable
如果你向上面一样使用 **ForAll** 方法,那么你可以使用 **RemoteService** 特性来禁用某个服务或方法。请在 **服务的接口** 中使用该特性,而不是在服务类中。
#### 包装结果
ABP通过 **AjaxResponse** 对象来 **包装** 动态Web API Actions的返回值。你可以Enable/Disable包装对每个方法或应用服务。如下所示:
```csharp
public interface ITestAppService : IApplicationService
{
[DontWrapResult]
DoItOutput DoIt(DoItInput input);
}
```
我们对DoIt禁用了包装。这个特性应该在添加在接口里面的方法描述上,而不是扩展类上。
如果你想更精确的控制返回值到客户端,禁用包装是非常有用的。特别是在使用第三方客户端库的时候,禁用包装是有必要的,因为ABP的标准包装 **AjaxResponse** 可能不能与之一起使用。在这种情况下,你也应该自己处理异常,因为异常处理会被禁用掉(DontWrapResult特性有个属性:WrapOnError,该属性可以被用来开启异常处理并对异常进行包装)。
>注意:动态脚本代理能够使用该结果,如果该结果是未包装,而且且能够正常的被处理。
#### 关于参数绑定
ABP在运行时创建API Controllers。所以ASP.NET Web API 的[模型和参数绑定](http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api)被使用来绑定模型和参数。你可以读取该[文档](http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api)获取更多信息。
#### FormUri 和 FormBody 特性
**FromUri 和 FromBody** 特性能够在服务接口中被使用增进对绑定的控制。
#### 数据传输对象 VS 原生类型
对于应用服务和Web API控制器,我强烈建议使用DTO来作为方法参数。但是你也可以使用原生类型(如:string,int,bool ...或可空类型,如:int?,bool? ...) 作为服务方法的参数。可以使用多个参数;但是,在这些参数中有且只能有一个 **Complex-Type** 参数,这是ASP.NET Web API 规定的。
- 文章&教程
- Abp
- 1.1ABP总体介绍-入门介绍
- 1.2ABP总体介绍-多层架构体系
- 1.3ABP总体介绍-模块系统
- 1.4ABP总体介绍-启动配置
- 1.5ABP总体介绍-多租户
- 1.6ABP总体介绍-集成OWIN
- 2.1ABP公共结构-依赖注入
- 2.2ABP公共结构-会话管理
- 2.3ABP公共结构-缓存管理
- 2.4ABP公共结构-日志管理
- 2.5ABP公共结构-设置管理
- 2.6ABP公共结构-时区设置
- 3.1ABP领域层-实体
- 3.2ABP领域层-值对象
- 3.3ABP领域层-仓储
- 3.4ABP领域层-领域服务
- 3.5ABP领域层-工作单元
- 3.6ABP领域层-领域事件
- 3.7ABP领域层-数据过滤器
- 4.1ABP应用层-应用服务
- 4.2ABP应用层-数据传输对象
- 4.3ABP应用层-数据传输对象验证
- 4.4ABP应用层-权限认证
- 4.5ABP应用层-功能管理
- 4.6ABP应用层-审计日志
- 5.1ABP分布式服务-ASP.NET WebApi
- 5.2ABP分布式服务-动态WebApi层
- 5.3ABP分布式服务-集成OData
- 5.4ABP分布式服务-集成SwaggerUI
- 6.1ABP表现层-Mvc控制器
- 6.2ABP表现层-Mvc视图
- 6.3ABP表现层-本地化
- 6.4ABP表现层-导航栏
- 6.5ABP表现层-异常处理
- 6.6.2-AJAX
- 6.6.3-Notification
- 6.6.4-Message
- 6.6.5-UIBlockBusy
- 6.6.6-EventBus
- 6.6.7-Logging
- 6.6.8-OtherUtilities
- 6.6ABP表现层-JavascriptAPI
- 6.7ABP表现层-嵌入资源文件
- 6.8ASP.NET-Core
- 6.9CSRF和XSRF保护
- 7.1ABP后台服务-后台作业和工人
- 7.2ABP后台服务-集成Hangfire
- 8.1ABP实时服务-通知系统
- 8.2ABP实时服务-集成SignalR
- 9.1ABP基础设施层-集成Entity Framework
- 9.2ABP基础设施层-集成NHibernate
- 9.3ABP基础设施层-集成Entity Framework Core
- abp合并版160929
- md文档排版规范
- AbpZero
- 1.1ABPZero-概述
- 1.2ABPZero-安装
- 1.3ABPZero-启动模板
- 1.4ABPZero-启动模板Core
- 2.1ABPZero-多租户管理
- 2.2ABPZero-版本管理
- 2.4ABPZero-组织单位管理