文檔目錄
本節內容:
創建動態Web Api 控制器
這個文檔是關於Asp.net Web Api的,如果你對Asp.net Core感興趣,可查看Asp.net Core文檔。
ABP可為你的應用層自動創建Asp.net Web Api層,假設我們有一個如下所示的應用服務:
public interface ITaskAppService : IApplicationService { GetTasksOutput GetTasks(GetTasksInput input); void UpdateTask(UpdateTaskInput input); void CreateTask(CreateTaskInput input); }
我們想把這個服務作為一個Web Api控制器暴露給客戶端,ABP可通過一行配置為這個應用服務,自動動態創建一個Web Api控制器:
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder.For<ITaskAppService>("tasksystem/task").Build();
這就完事了。一個api控制器被創建在地址“/api/services/tasksystem/task”下,所有的方法客戶端都可以使用。這個配置應當在你的模塊的Initialize方法裡完成。
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世界裡就是這樣約定俗成。
ForAll 方法
在一個應用裡可能有很多應用服務,一個一個地創建api控制器會是一件乏味並易遺漏的工作,DynamicApiControllerBuilder提供了一個為所有應用服務創建web api控制器一次調用的方法,例如:
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder .ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem") .Build();
ForAll方法是一個接受一個接口的泛型,第一個參數是程序集,它包含繼承自前面所指定接口的類,第二個服務的命名空間前綴,假設我們有一個包含ITaskAppService和IPersonAppService的程序集,應用上述配置,服務將是:“/api/services/tasksystem/task”和“/api/services/tasksystem/person”。為計算服務名:Service和AppService後綴和I前綴(接口)會被移除,服務名也被轉換成駝峰形式。如果你不喜歡這種約定,有一個“WithServicename”方法可以確定命名。還有一個Where方法可過濾服務,這在你想為除了少數幾個外的所有應用服務創建api控制器的時候,非常有用。
重寫 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();
這段代碼裡,我們為一個程序集裡的所有應用服務創建Web Api控制器,然後為一個單獨的應用服務(ITaskAppService)重寫配置,忽略CreateTask方法。
ForMethod
當使用ForAll方法時,我們可用ForMethods方法進行更好的調用 ,例如:
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder .ForAll<IApplicationService>(Assembly.GetExecutingAssembly(), "app") .ForMethods(builder => { if (builder.Method.IsDefined(typeof(MyIgnoreApiAttribute))) { builder.DontCreate = true; } }) .Build();
在這個示例裡,用一個自定義特性(MyIgnoreApiAttribute)來檢查所有方法,不為標記了這個特性的方法創建動態web api控制器。
Http 動詞
默認地,所有方法被創建成POST,所以一個客戶端應用發送post請求來使用已創建的web api的actions。我們可以把這種行為修改成不同的方式。
WithVerbMethod
我們可以為一個方法使用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.Asp.net.WebApi.Core的nuget包,並引用它。
命名約定
你可以使用WithconvertionalVerbs方法,代替為每個方法聲明HTTP動詞,如下所示:
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder .ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem") .WithConventionalVerbs() .Build();
這種情況下,以方法名的前綴確定HTTP動詞:
但我們也可以用前面據說的方法重寫它。
Api 浏覽器
默認情況下,所有的動態Web api 控制器都會顯示在Api浏覽器裡(例如:Swagger),不過你可以通過flunet DynamicApicontrollerBuilder Api或RemoteService特性來改變這種行為。
RemoteService 特性
你可為任何的接口或方法使用RemoeteService來定義啟用/禁用(IsEnabled)動態Api或Api浏覽器設置(IsMetadataEnabled)。
動態Javascript代理
你可以通過Javascript的ajax使用動態創建的web api控制器,ABP也通過為api控制器創建動態Javascript代理來簡化調用。所以,你可以用像javascript調用函數那樣的方式來調用一個動態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),你可以注冊done, fail, then等回調函數,服務方法內部使用abp.ajax,它們在需要的時候處理錯誤並顯示。
AJJX 參數
你可能想傳遞自定義參數給代理方法,你可以把它們作為第二個參數,如下所示:
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的所有參數在此都是可用的。
除了標准的jQuery.ajax參數外,你可以給AJAX選項添加abpHandleError:false,以便禁用出錯時自動顯示出錯信息。
單獨服務腳本
“/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; }); } ]); })();
我們可以使用它的名稱(包含命名空間)注入一個service,然後就可以如調用常規的Javascript函數那樣調用它的函數,注意:我們注冊success處理程序(代替done),因為這就像在angular的$http服務裡,ABP使用Angularjs的$http服務,如果你想傳遞$http的configuration,你可以傳遞一個configuration對象,作為服務方法的最後一個參數。
為了使用自動生成的服務,你應該在你的頁面裡包含必要的腳本:
<script src="~/Abp/Framework/scripts/libs/angularjs/abp.ng.js"></script> <script src="~/api/AbpServiceProxies/GetAll?type=angular"></script>
啟用/禁用
如果你上面陳述的那樣,使用ForAll方法,你可以為一個服務或方法,使用RemoteService特性來禁用它,要在服務接口上使用這個特性,而不是服務類上。
包裝結果
ABP通過AjaxResponse對象包裝動態Web Api的Action返回值,更多信息查看ajax文檔。你可以為每個方法或每個應用服務啟用/禁用包裝,請看如下應用服務示例:
public interface ITestAppService : IApplicationService { [DontWrapResult] DoItOutput DoIt(DoItInput input); }
我們為DoIt方法禁用了包裝,這個屬性要聲明在接口裡,而不是實現的類裡。
如果你想更好地控制返回給客戶端的值,不包裝是非常有用的,尤其,在使用不支持ABP標准的AjaxResponse的第三方客戶端庫時,這種情況下,你也需要自己處理異常,因為異常處理也會被禁用(DontWrapResult特性擁有WrapOnError屬性,它能啟用異常的處理和包裝)。
注意:動態javascript代理可以理解沒有包裝的結果,並用適應的方式處理結果。
關於參數綁定
ABP在運行時創建Api控制器,所以,Asp.net Web Api的模型與參數綁定用來綁定模型和參數,更多信息你可以閱讀它們的文檔。
FormUri 和 FormBody 特性
FormUri和FormBody特性可用在服務接口裡,優先控制綁定。
DTO vs 簡單類型
我們強烈建議為應用服務和web api控制器的方法使用Dto,但你可以使用簡單類型(如string,int,bool...或nullable類型,如int?,bool?...)作為服務參數,可用多個簡單類型參數,但只能用一個復雜類型參數(由於Asp.net Web Api的限制)。