1. 文章目的
隨着WebApiClient的不斷完善,越來越多開發者選擇WebApiClient替換原生的HttpClient,然而在應用到實際項目中多多少少會遇到一些項目結合上的疑問和困難,本文將以WebApiClient使用者的身份,在Asp.net core mvc
項目中使用WebApiClient來請求百度地圖服務接口,以展示WebApiClient的使用技巧。
2. 百度地圖服務接口
-
坐標轉換接口
http://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak=你的密鑰
3. 接口分析
通過分析百度地圖的接口,我們發現:
- 所有接口都在api.map.baidu.com這個域名上;
- ak參數是一個客戶端身份標識的參數,所有請求接口都需要附加這個ak值;
- 接口中需要的116.403874,39.914888這種參數值,實際是(經度,緯度),為兩個值組成;
- from和to是枚舉數值類型;
在我們進行Coding的時候,應該重點考慮這些共性,以減少重復的工作內容。
4. 接口聲明
4.1 公共域名
[HttpHost("http://api.map.baidu.com/")]
public interface IBdMapApi : IHttpApi
{
}
4.2 公共的AK參數
我們要實現一個接口級或方法級的ApiAction特性,用於給請求路徑增加公共的ak參數:
/// <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特性追加到接口上:
[HttpHost("http://api.map.baidu.com/")]
[Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")]
public interface IBdMapApi : IHttpApi
{
}
4.3 靜態圖staticimage接口
參照接口文檔,聲明最初的StaticImage接口:
[HttpGet("staticimage/v2")]
ITask<Stream> StaticImageAsync(
string center,
int width = 300,
int height = 200,
int zoom = 11,
int mcode = 666666);
目前center參數是string類型,約束性非常弱,與接口要求的(經度,緯度)這種格式數據差異比較大。所以我們應該定一個繼承自IApiParameterable的BdLocation類型,將傳入的經度和緯度轉換為這種文本格式:
/// <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);
4.4 坐標轉換Geoconv接口
依照文檔,編寫出最初的接口
[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);
4.5 完整的接口聲明
/// <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);
}
5. 接口的依賴注入
WebApiClient的HttpApiClient創建的代理實例,適合使用單例模式,在支持依賴注入的項目開發中,應盡量使用依賴注入來完成HttpApiClient的創建和生命周期管理。
5.1 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()));
}
}
5.2 接收和使用IBdMapApi代理實例
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();
}
}
6. 監視請求提交的內容
WebApiClient對Http請求進行的高度抽象,只有聲明,沒有實現,在沒有熟悉WebApiClient的情況下,我們開發中可能需要在請求發送的內容進行監視,從而知道是否符合服務器的接口數據要求。在不使用第三方工具比如Fiddler等的情況下,我們可以為接口修飾一個自定義過濾器,在過濾器里實現訪打印求消息內容的能力。
6.1 定義TraceFilter過濾器
/// <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);
}
}
6.2 接口關聯TraceFilter
/// <summary>
/// 定義百度地圖接口
/// </summary>
[TraceFilter]
[Ak("qde9uxuEhwMlngvTbWGo3BIQOKfqvjdc")]
[HttpHost("http://api.map.baidu.com/")]
public interface IBdMapApi : IHttpApi
{
}
6.3 查看請求內容
開啟程序調試,輸出窗口里打印
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
7. 結束語
博主為WebApiClient庫的作者,致力於站在使用者的角度去設計WebApiClient,歡迎大家給WebApiClient提建議。