構建動態Web API控制器
ABP可以自動地為應用層生成Web API 層。比如說我們之前建立的應用層:
namespace Noah.ChargeStation.Application.CitiesApp { public interface ICityAppService:IApplicationService { GetCitiesOutput GetCities(GetCityInput input); Task<GetCitiesOutput> GetCitiesAsync(GetCityInput input); void UpdateCity(CityInput input); Task UpdateCityAsync(CityInput input); void CreateCity(CreateCityInput input); Task CreateCityAsync(CreateCityInput input); } }
我們想要把這些服務作為Web API 控制器暴露給客戶端。ABP通過一句程式碼就可以自動、動態地為該應用層建立Web API 控制器,在Web API層的Api資料夾下找到xxxWebApiModule類的Initialize方法,新增程式碼:
DynamicApiControllerBuilder.For<ICityAppService>("ChargeStationAPI/City").Build();
你要做的就這麼多!這樣,在“/api/services/chargeStationAPI/City”的地方就建立了一個API控制器,所有的方法客戶端都可以使用。
ICityAppService是我們想要使用Api 控制器包裝的應用服務。對於應用服務這不是強制的而是傳統推薦的方式。“ChargeStationAPI/CIty”是一個有著任意名稱空間的控制器名字。你應該至少定義一級的名稱空間,也可以定義更深層次的名稱空間,
比如“myCompany/myApplication/myNamespace1/myNamespace2/myServiceName”。“/api/services/”是所有的Web API控制器的字首 。因而API控制器的地址將會是這個樣子的“/api/services/ChargeStationAPI/City”,GetCities方
法的地址就是“/api/services/ChargeStationAPI/City/getCities”。因為在Javascript中的命名慣例是camelCase,所以方法名就自動轉成了camelCase命名的格式。
ForAll 方法
在一個應用中,我們可能有許多應用服務,一個一個地構建api控制器也許是一個乏味而難忘的工作。DynamicAPIControllerBuilder提供了一種方法,可以在一次呼叫中,對所有的應用服務建立web api 控制器。例如:
DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(ChargeStationApplicationModule).Assembly, "ChargeStationAPI") .Build();
ForAll方法是一個接收介面的泛型方法。第一個引數是程式集物件,該程式集包含從給定介面派生的類。最後一個引數是服務名稱空間的字尾。比如我們在給定程式集中有ICityAppService和IProvinceAppService。對於該配置,服務就是
“/api/services/ChargeStationAPI/CityApp”和“/api/services/ChargeStationAPI/ProvinceApp”。計算服務名的過程是這樣的:移除服務介面的Service和AppService字尾以及I字首。而且,服務名格式被轉成了camelCase格式。如果不喜歡
這個轉換,那麼你可以通過“WithServiceName”方法決定你命名。除此之外,還有一個Where方法來過濾服務。如果你要為所有的應用服務構建, 其次在此基礎上再排除一些,那麼這很有用。
重寫ForAll方法
可以在ForAll方法之後重寫配置。例如:
DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(ChargeStationApplicationModule).Assembly, "ChargeStationAPI") .Build();//告訴生成器為所有實現了IApplicationService介面的服務方法建立api控制器 DynamicApiControllerBuilder .For<ICityAppService>("ChargeStationAPI/City") .ForMethod("CreateCity").DontCreateAction() .Build();//告訴生成器不要生成"ChargeStationAPI/City"的"CreateCity"方法
Http 動詞
所有的方法預設都是以POST方式建立的。因此,為了使用建立的Web Api方法,客戶端應該傳送post請求。我們通過不同的方式改變這個行為。
WithVerb方法
可以為一個方法使用WithVerb,像下面這樣:
DynamicApiControllerBuilder.For<ICityAppService>("ChargeStationAPI/City") .ForMethod("getCities").WithVerb(HttpVerb.Get) .Build();
下面直接演示一下:
我們直接在Url位址列傳送一次get請求,發現有一個Json格式的資料,錯誤資訊很明確,“輸入是null”。雖然報錯了,至少可以肯定的是已經生成了web api控制器,只是該控制器需要一個輸入引數而已。
HTTP特性
我們可以把HttpGet,HttpPost…特性加到服務介面的方法上:
public interface ICityAppService:IApplicationService { [HttpGet] GetCitiesOutput GetCities(GetCityInput input); [HttpGet] Task<GetCitiesOutput> GetCitiesAsync(GetCityInput input); [HttpPost] void UpdateCity(CityInput input); [HttpPost] Task UpdateCityAsync(CityInput input); [HttpPost] void CreateCity(CreateCityInput input); [HttpPost] Task CreateCityAsync(CreateCityInput input); }
要使用這些HTTP特性,就必須嚮應用層專案中新增Microsoft.AspNet.WebApi.Core Nuget包的引用。新增了HTTP特性之後,就不需要使用上面的WithVerb方法了。
命名慣例
不需要為每一個方法宣告HTTP動詞,可以使用WithConventionalVerbs方法:
DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(ChargeStationApplicationModule).Assembly, "ChargeStationAPI") .WithConventionalVerbs()//根據方法名使用慣例HTTP動詞,預設對於所有的action使用Post .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:
Javascript代理是動態建立的。使用之前應該將下面動態的指令碼包括在頁面上。
<script src="~/api/AbpServiceProxies/GetAll"></script>
可以註冊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!'); });
單獨服務指令碼
'/api/AbpServiceProxies/GetAll'在一個檔案中生成所有的服務代理。使用'/api/AbpServiceProxies/Get?name=serviceName'也可以生成一個單獨的服務代理,只需要在頁面中包括下面的程式碼:
<script src="/api/AbpServiceProxies/Get?name=tasksystem/task" type="text/javascript"></script>
Angular支援
ABP可以作為angular服務暴露動態的api控制器。
(function() { angular.module('ChargeStationAPI').controller('CityListController', [ '$scope', 'abp.services.chargeStationAPI.City', function($scope, cityService) { var vm = this; vm.cities = []; taskService.getCities({ ProvinceCode: 1 }).success(function(result) { vm.cities = result.cities; }); } ]); })();
我們可以使用服務的名字(包含名稱空間)注射一個服務。然後,可以作為正常的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>