前言
本篇文章的內容是WebApiClient應用說明篇,如果你沒有了解過WebApiClient,可以先閱讀以下相關文章:
- WebApi client 的面向切面編程
- 我來給.Net設計一款HttpClient
- .Net45下HttpClient的幾個缺陷
- .net的retrofit--WebApiClient庫
- .net的retrofit--WebApiClient庫深入篇
- .net的retrofit--WebApiClient底層篇
背景
隨着Wcf、Webservice等的SOAP的份額越來越少,以及Restful Api的興起,目前幾乎所有新平台提供的接口,都只提供Restful Api,而.net平台下,沒有類似Wcf這么簡單的客戶端可以直接請求和管理這些Restful api的解決方案,.net平台提供的HttpWebRequest、WebClient和HttpClient這三個類庫,可用於實現Http接口的請求,但相比wcf得益於soap自我描述實現的自動生成客戶端調用代碼,Restful就沒這么方便了,無論使用HttpWebRequest還是HttpClient,都需要對每個Api縮寫沉長的調用代碼。
使用WebApiClient
WebApiClient是在這樣的背景下產生一款Http全異步的客戶端庫,它的出現,大幅度減輕了接口調用者的工作量,而且在調用Http接口上還非常容易維護和更新,還可以輕松應對設計不太友好的一些http接口。
使用WebApiClient,編程人員不再需要手動實現路徑拼接、參數拼接、請求體組裝和響應映射為模型這些繁瑣的過程,以下為WebApiClient應用到項目中的一般流程:
1 聲明http接口的Interface
[JsonReturn]
public interface IIotRemotePush : IDisposable
{
/// <summary>
/// 創建遠程推送賬號
/// </summary>
/// <param name="auth">授權</param>
/// <returns></returns>
[HttpPost("/v1/RemotePush/CreateAccount")]
ITask<ApiResult<PushAccount>> CreateAccountAsync(IotBasicAuth auth);
/// <summary>
/// 獲取推送服務信息
/// </summary>
/// <param name="id">pushId</param>
/// <returns></returns>
[HttpGet("/v1/Mqtt/GetPushSevice?id={id}")]
ITask<ApiResult<MqttService>> GetPushSeviceAsync(string id);
}
/// <summary>
/// Api結果接口
/// </summary>
public interface IApiResult
{
/// <summary>
/// 錯誤碼
/// </summary>
ErrorCode Code { get; set; }
/// <summary>
/// 相關提示信息
/// </summary>
string Msg { get; set; }
}
/// <summary>
/// 表示Api結果
/// </summary>
public class ApiResult<T> : IApiResult
{
/// <summary>
/// 錯誤碼
/// </summary>
public ErrorCode Code { get; set; }
/// <summary>
/// 相關提示信息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 業務數據
/// </summary>
public T Data { get; set; }
}
2 調用http接口
WebApiClient不需要開者實現接口,使用HttpApiClient.Create方法可以動態創建接口的實現類的實例,調用實例的方法,就完成一個Api的請求。
using (var iotApi = HttpApiClient.Create<IIotRemotePush>())
{
var auth = new IotBasicAuth(config.AppId, config.AppToken);
var createResult = await iotApi.CreateAccountAsync(auth);
if (createResult.Code != ErrorCode.NoError)
{
return null;
}
config.PushId = createResult.Data.Id;
config.PushToken = createResult.Data.Token;
await db.SaveChangesAsync();
return config;
}
3 異常定義與異常處理
在以上接口中,接口返回的都是ApiResult
/// <summary>
/// 表示Iot異常
/// </summary>
public class IotException : Exception
{
/// <summary>
/// 錯誤碼
/// </summary>
public ErrorCode ErrorCode { get; private set; }
/// <summary>
/// Iot異常
/// </summary>
/// <param name="apiResult">api結果值</param>
public IotException(IApiResult apiResult)
: base(apiResult.Msg)
{
this.ErrorCode = apiResult.Code;
}
}
我們還應該在Interface上擴展JsonResult,用於將ApiResult的ErrorCode轉換為IotException,並拋出:
/// <summary>
/// 表示IotJson結果
/// </summary>
public class IotJsonResultAttribute : JsonReturnAttribute
{
protected override async Task<object> GetTaskResult(ApiActionContext context)
{
var apiResult = await base.GetTaskResult(context) as IApiResult;
if (apiResult != null && apiResult.Code != ErrorCode.NoError)
{
throw new IotException(apiResult);
}
return apiResult;
}
}
然后將新的IotJsonResultAttribute在Interface上替換JsonReturnAttribute:
[IotJsonResult]
public interface IIotRemotePush : IDisposable
{
...
}
最后,調用http接口的時候,可以使用Handle()擴展方法處理異常:
using (var iotApi = HttpApiClient.Create<IIotRemotePush>())
{
var auth = new IotBasicAuth(config.AppId, config.AppToken);
var createResult = await iotApi.CreateAccountAsync(auth)
.Handle()
.WhenCatch<IotException>(ex =>
{
// process exception
return default(ApiResult<PushAccount>);
})
.WhenCatch<Exception>(ex =>
{
// process exception
return default(ApiResult<PushAccount>);
});
if (createResult == null)
{
return null;
}
config.PushId = createResult.Data.Id;
config.PushToken = createResult.Data.Token;
await db.SaveChangesAsync();
return config;
}
WebApiClient現狀
WebApiClient項目目前已加入.NET China Foundation,正在為.net開源作出自己的一點貢獻。