本篇目錄
- 構建動態Web API控制器
- 動態Javascript代理
- Ajax參數
- 單一服務腳本
- Angular支持
- Durandal支持
- 返回結果封裝【2016/3/28 更新】
- 關於參數綁定
構建動態Web API控制器
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格式。
ForAll 方法
在應用服務層可能會有很多的應用服務,如果要為這些應用服務都構建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 方法
在ForAll方法之后我們可以重寫配置。例如:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/task")
.ForMethod("CreateTask").DontCreateAction()
.Build();
在上面的代碼中,我們為一個程序集中所有的應用服務構建了動態的Web API控制器。然后又為一個應用服務(ITaskAppService)重寫了配置,目的是忽略該應用服務中的CreateTask方法。
Http動詞
默認情況下,創建的方法都只能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動詞會由方法名的前綴決定:
- Get:方法名以Get開頭。
- Put:方法名以Put或Update開頭。
- Delete:方法名以Delete或Remove開頭。
- Post:方法名以Post或Create開頭。
- 其他情況,Post是HTTP動詞的默認值
我們可以通過對特定的方法使用WithVerb方法或者HTTP特性來覆蓋上述慣例。
動態Javascript代理
在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參數
你可以把一個自定義的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>
Angular支持
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>
Durandal支持
ABP可以在一個Durandal應用的模塊中注入服務代理。看下面的viewmodel:
define(['service!tasksystem/task'],
function (taskService) {
//taskService can be used here
});
ABP配置Durandal(實際上是Require.js)來理解這個'service!'前綴,然后注入合適的javascript服務代理。
返回結果封裝
ABP通過 AjaxResponse封裝了動態Web API的action的返回值。查看《Ajax文檔》獲取更多關於封裝的信息。你可以為每個應用服務或者每個方法開啟或者禁用封裝。看下面這個應用服務的例子:
public interface ITestAppService : IApplicationService
{
[DontWrapResult]
DoItOutput DoIt(DoItInput input);
}
這里我們為DoIt方法禁用了封裝。這個特性應該為接口聲明而不是實現類。
如果你想更好地控制客戶端的返回值,那么不封裝返回的結果可能是很有用的。特別地,當使用不能和ABP標准的AjaxResponse協作的第三方客戶端庫時,可能需要禁用封裝。這種情況下,你要自己處理異常。
注意:動態javascript代理可以理解返回的結果是否封裝和運行正常。
關於參數綁定
ABP在運行時創建了API控制器。因此,ASP.NET Web API的模型和參數綁定可以用於綁定模型和參數。
FromUri和FromBody特性
為了在綁定時進行高級控制,可以在服務接口上使用FromUri和FromBody特性。
DTOs vs原始類型
我們強烈建議為應用服務和Web API控制器的方法使用DTO作為參數類型,但是你也可以使用原始類型(如string,int,bool或者可空的類型如int?,bool?)作為參數類型。雖然可以在應用服務中使用不止一個參數,但是最好用一個復雜的類型將多個參數整合起來,否則客戶端就不會生成動態代理服務。在日志記錄中就會看到如下圖所示的錯誤:

