隨着WebApiClient的不斷完善,愈來愈多開發者選擇WebApiClient替換原生的HttpClient,然而在應用到實際項目中多多少少會遇到一些項目結合上的疑問和困難,本文將以WebApiClient使用者的身份,在Asp.net core mvc
項目中使用WebApiClient來請求百度地圖服務接口,以展現WebApiClient的使用技巧。git
座標轉換接口
http://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak=你的密鑰c#
經過分析百度地圖的接口,咱們發現:api
在咱們進行Coding的時候,應該重點考慮這些共性,以減小重複的工做內容。服務器
[HttpHost("http://api.map.baidu.com/")] public interface IBdMapApi : IHttpApi { }
咱們要實現一個接口級或方法級的ApiAction特性,用於給請求路徑增長公共的ak參數:mvc
/// <summary> /// 表示百度AK信息 /// </summary> public class AkAttribute : ApiActionAttribute { private readonly string ak; /// <summary> /// 百度AK信息 /// 執行時追加到請求query /// </summary> /// <param name="ak"></param> public AkAttribute(string ak) { this.ak = ak; } /// <summary> /// 請求前 /// </summary> /// <param name="context"></param> /// <returns></returns> public override async Task BeforeRequestAsync(ApiActionContext context) { context.RequestMessage.AddUrlQuery("ak", this.ak); await Task.CompletedTask; }
而後把Ak特性追加到接口上:asp.net
[HttpHost("http://api.map.baidu.com/")] [Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")] public interface IBdMapApi : IHttpApi { }
參照接口文檔,聲明最初的StaticImage接口:async
[HttpGet("staticimage/v2")] ITask<Stream> StaticImageAsync( string center, int width = 300, int height = 200, int zoom = 11, int mcode = 666666);
目前center參數是string類型,約束性很是弱,與接口要求的(經度,緯度)這種格式數據差別比較大。因此咱們應該定一個繼承自IApiParameterable的BdLocation類型,將傳入的經度和緯度轉換爲這種文本格式:ide
/// <summary> /// 表示位置信息 /// </summary> public class BdLocation : IApiParameterable { /// <summary> /// 獲取位置值 /// </summary> public string Value { get; private set; } /// <summary> /// 位置信息 /// 執行時追加到請求query /// </summary> /// <param name="lng">經</param> /// <param name="lat">緯</param> public BdLocation(decimal lng, decimal lat) { this.Value = $"{lng},{lat}"; } public override string ToString() { return this.Value; } /// <summary> /// 自解釋模式 /// </summary> /// <param name="context"></param> /// <param name="parameter"></param> /// <returns></returns> Task IApiParameterable.BeforeRequestAsync(ApiActionContext context, ApiParameterDescriptor parameter) { context.RequestMessage.AddUrlQuery(parameter.Name, this.Value); return Task.CompletedTask; } }
修改後StaticImage接口修改成:工具
[HttpGet("staticimage/v2")] ITask<Stream> StaticImageAsync( BdLocation center, int width = 300, int height = 200, int zoom = 11, int mcode = 666666);
依照文檔,編寫出最初的接口
[HttpGet("geoconv/v1/")] ITask<string> GeoconvAsync( string coords, int from = 1, int to = 5);
和StaticImage接口同樣,咱們還須要合理修改這個接口的參數約束,coords實際爲BdLocation類型, from和to能夠修改成枚舉類型,返回值string修改成強類型的模型,修改後的接口爲:
[HttpGet("geoconv/v1/")] ITask<BdResult<BdPoint[]>> GeoconvAsync( BdLocation coords, BdFrom from = BdFrom.wgs84, BdTo to = BdTo.bd09ll);
/// <summary> /// 定義百度地圖接口 /// </summary> [Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")] [HttpHost("http://api.map.baidu.com/")] public interface IBdMapApi : IHttpApi { /// <summary> /// 靜態圖 /// </summary> /// <param name="center"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="zoom"></param> /// <param name="mcode"></param> /// <returns></returns> // http://api.map.baidu.com/staticimage/v2?ak=你的密鑰&mcode=666666¢er=116.403874,39.914888&width=300&height=200&zoom=11 [HttpGet("staticimage/v2")] ITask<Stream> StaticImageAsync( BdLocation center, int width = 300, int height = 200, int zoom = 11, int mcode = 666666); /// <summary> /// 座標轉換 /// </summary> /// <param name="coords"></param> /// <param name="from"></param> /// <param name="to"></param> /// <returns></returns> // http://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak=你的密鑰 //GET請求 [HttpGet("geoconv/v1/")] ITask<BdResult<BdPoint[]>> GeoconvAsync( BdLocation coords, BdFrom from = BdFrom.wgs84, BdTo to = BdTo.bd09ll); }
WebApiClient的HttpApiClient建立的代理實例,適合使用單例模式,在支持依賴注入的項目開發中,應儘可能使用依賴注入來完成HttpApiClient的建立和生命週期管理。
Asp.net core
的依賴注入在ConfigureServices方法裏添加IBdMapApi的注入配置
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSingleton(HttpApiClient.Create<IBdMapApi>()); ...... }
若是項目裏聲明瞭不少接口,好比IBaiduApi、ITengxunApi等等,能夠循環批量注入:
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var apis = this.GetType().Assembly.GetTypes().Where(item => typeof(IHttpApi).IsAssignableFrom(item)); foreach (var api in apis) { services.AddSingleton(api, HttpApiClient.Create(api, new HttpApiConfig())); } }
public class HomeController : Controller { private readonly IBdMapApi bdMapApi; public HomeController(IBdMapApi bdMapApi) { this.bdMapApi = bdMapApi; } public async Task<IActionResult> Index() { var image = await this.bdMapApi.StaticImageAsync(new BdLocation(116.403874m, 39.914888m)); var geoResult = await this.bdMapApi.GeoconvAsync(new BdLocation(116.403874m, 39.914888m)); return View(); } }
WebApiClient對Http請求進行的高度抽象,只有聲明,沒有實現,在沒有熟悉WebApiClient的狀況下,咱們開發中可能須要在請求發送的內容進行監視,從而知道是否符合服務器的接口數據要求。在不使用第三方工具好比Fiddler等的狀況下,咱們能夠爲接口修飾一個自定義過濾器,在過濾器裏實現訪打印求消息內容的能力。
/// <summary> /// 請求內容追蹤過濾器 /// </summary> public class TraceFilter : ApiActionFilterAttribute { /// <summary> /// 打印請求內容 /// </summary> /// <param name="context"></param> /// <returns></returns> public override async Task OnBeginRequestAsync(ApiActionContext context) { var request = await context.RequestMessage.ToStringAsync(); System.Diagnostics.Debug.Print(request); } }
/// <summary> /// 定義百度地圖接口 /// </summary> [TraceFilter] [Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")] [HttpHost("http://api.map.baidu.com/")] public interface IBdMapApi : IHttpApi { }
開啓程序調試,輸出窗口裏打印
GET /staticimage/v2?ak=qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc¢er=116.403874%2c39.914888&width=300&height=200&zoom=11&mcode=666666 HTTP/2.0 Host: api.map.baidu.com GET /geoconv/v1/?ak=qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc&coords=116.403874%2c39.914888&from=1&to=5 HTTP/2.0 Host: api.map.baidu.com
博主爲WebApiClient庫的做者,致力於站在使用者的角度去設計WebApiClient,歡迎你們給WebApiClient提建議。