動態Web API層


返回總目錄

本篇目錄

構建動態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?)作為參數類型。雖然可以在應用服務中使用不止一個參數,但是最好用一個復雜的類型將多個參數整合起來,否則客戶端就不會生成動態代理服務。在日志記錄中就會看到如下圖所示的錯誤:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM