返回总目录
ABP可以自动地为应用层生成Web API 层。比如说我们有一个应用层如下所示:
public interface ITaskAppService : IApplicationService
{
GetTasksOutput GetTasks(GetTasksInput input);
void UpdateTask(UpdateTaskInput input);
void CreateTask(CreateTaskInput input);
}
我们想把这个服务作为Web API控制器暴露给客户端。ABP只需要一行配置就可以为该应用服务创建一个Web API控制器:
DynamicApiControllerBuilder.For<ITaskAppService>("tasksystem/task").Build();
OK了!在地址为'/api/services/tasksystem/task'的地方就创建了一个API控制器,现在客户端可以使用该应用服务的所有方法。这个配置应该在模块的Initlize方法中完成。
我们使用一个API控制器封装的ITaskAppService是一个应用服务。使用API控制器对应用服务进行封装不是强制的,但是这是传统推荐的方式。 "tasksystem/task"一个具有随机命名空间的API控制器的名字。你应该至少定义一级的命名空间,但是你也可以定义更深层次的命名空间,比如 "myCompany/myApplication/myNamespace1/myNamespace2/myServiceName"。 '/api/services'是所有动态生成的Web API控制器的前缀。因此,该API控制器的地址将会是这个样子的 '/api/services/tasksystem/task',而GetTasks方法的地址将会是 '/api/services/tasksystem/task/getTasks'。因为在javascript中惯例遵循 camelCase规则,所以方法名都转成了camelCase格式。
在应用服务层可能会有很多的应用服务,如果要为这些应用服务都构建API控制器的话,一个一个地构建简直是费时费力的事情。没关系,ABP中的DynamicApiControllerBuilder提供了一个为所有应用服务构建Web API控制器的方法,这样我们只需要调用一次就行了。例如:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
ForAll方法是接收接口类型的泛型方法。第一个参数是一个程序集,该程序集中含有派生自给定接口的类。最后一个参数是服务前缀的命名空间。比如说我们在给定的程序集中有ITaskAppService和IPersonAppService,对于这个配置的话,服务地址将会是 '/api/services/tasksystem/task' 和 '/api/services/tasksystem/person'。计算服务名称的方法是:移除Service或者AppService后缀,以及I前缀(对于接口来说)。此外,服务名称会转成camel Case(驼峰命名)的格式。如果你不喜欢这种转换,那么使用'WithServiceName'来决定服务发名称。此外,还有一个过滤服务的Where方法。除了个别应用服务之外,这个方法在你为其他所有的应用服务构建API控制器时很有用。
在ForAll方法之后我们可以重写配置。例如:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/task")
.ForMethod("CreateTask").DontCreateAction()
.Build();
在上面的代码中,我们为一个程序集中所有的应用服务构建了动态的Web API控制器。然后又为一个应用服务(ITaskAppService)重写了配置,目的是忽略该应用服务中的CreateTask方法。
默认情况下,创建的方法都只能POST请求。我们也可以使用不同的方法来改变这种行为。
WithVerb方法
我们可以为一个方法使用WithVerb,像下面那样:
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.CoreNuget包的引用。
命名规范
不用为每个方法都声明HTTP动词,你可以使用如下所示的WithConventionalVerbs方法:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.WithConventionalVerbs()
.Build();
在这种情况下,Http动词会由方法名的前缀决定:
我们可以通过对特定的方法使用WithVerb方法或者HTTP特性来覆盖上述惯例。
在Javascript中,可以经由Ajax使用动态创建的web api控制器。ABP通过为动态的web api控制器创建动态的Javascript代理简化了这个。因此,可以在Javascript中像调用一个function一样来调用一个动态的web api 控制器action:
abp.services.tasksystem.task.getTasks({
state: 1
}).done(function (result) {
//use result.tasks here...
});
Javascript代理是动态创建的。使用之前应该将下面动态的脚本包括在页面上。
<script src="/api/AbpServiceProxies/GetAll" type="text/javascript"></script>
服务方法返回了promise(查看jQuery.Deferred)。可以在返回的promise后面继续注册done,fail,then等回调函数。服务方法内部使用了abp.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!');
});
jQuery.ajax的所有参数在这里都是有效的。
'/api/AbpServiceProxies/GetAll'会在一个文件中生成所有的服务代理。使用'/api/AbpServiceProxies/Get?name=serviceName'也可以生成一个单独的服务代理,只需要在页面中包括下面的代码:
<script src="/api/AbpServiceProxies/Get?name=tasksystem/task" type="text/javascript"></script>
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(result) {
vm.tasks = result.tasks;
});
}
]);
})();
我们可以使用服务的名字(包含命名空间)注射一个服务。然后,可以作为正常的Javascript函数调用它的function。注意,我们注册到了success句柄上(而不是done),因为它就像在angular的\(http服务中。ABP使用AngularJs的\)http服务。如果
你想要传递$http配置,可以作为服务方法的最后一个参数传递一个配置对象。
要使用自动生成的服务,应该在页面中包含需要的脚本:
<script src="~/Abp/Framework/scripts/libs/angularjs/abp.ng.js"></script>
<script src="~/api/AbpServiceProxies/GetAll?type=angular"></script>
ABP可以在一个Durandal应用的模块中注入服务代理。看下面的viewmodel:
define(['service!tasksystem/task'],
function (taskService) {
//taskService can be used here
});
ABP配置Durandal(实际上是Require.js)来理解这个'service!'前缀,然后注入合适的javascript服务代理。
ABP在运行时创建了API控制器。因此,ASP.NET Web API的模型和参数绑定可以用于绑定模型和参数。
为了在绑定时进行高级控制,可以在服务接口上使用FromUri和FromBody特性。
我们强烈建议为应用服务和Web API控制器的方法使用DTO作为参数类型,但是你也可以使用原始类型(如string,int,bool或者可空的类型如int?,bool?)作为参数类型。虽然可以在应用服务中使用不止一个参数,但是最好用一个复杂的类型将多个参数整合起来,否则客户端就不会生成动态代理服务。在日志记录中就会看到如下图所示的错误: