.net的retrofit--WebApiClient庫

# 庫簡介

WebApiClient是開源在github上的一個httpClient客戶端庫,內部基於HttpClient開發,是一個只須要定義c#接口(interface),並打上相關特性,便可異步調用http-api的框架 ,支持.net framework4.5+、netcoreapp2.0和netstandard2.0。本文將詳細地講解如何使用WebApiClient進行http接口的調用,給.net開發者提供一種有別於傳統的http接口調用編程方式。git

1. 設計一個Get請求接口

1.1 最簡單的Get請求

public interface MyWebApi : IDisposable
{
    // GET http://www.mywebapi.com/webapi/user?account=laojiu
    [HttpGet("http://www.mywebapi.com/webapi/user")]
    ITask<string> GetUserByAccountAsync(string account);
}

var myWebApi = HttpApiClient.Create<MyWebApi>();
var userStr = await myWebApi.GetUserByAccountAsync("laojiu");
myWebApi.Dispose();

1.2 使用[HttpHost]特性

若是你有多個接口,並且都指向對一服務器,能夠將請求的域名抽出來放到HttpHost特性,接口的代碼以下:github

[HttpHost("http://www.mywebapi.com")]
public interface MyWebApi : IDisposable
{
    // GET /webapi/user?account=laojiu
    [HttpGet("/webapi/user")]
    ITask<string> GetUserByAccountAsync(string account);
}

1.3 使用強類型返回值處理xml或json

若是接口的返回內容是xml或json,你但願將它自動映射爲強類型的模型,須要給接口打上對應的[XmlReturn]或[JsonResult]。實際上有一個[AutoReturn],它會根據回覆頭標識,自動選擇不一樣的轉換器轉換爲TResult類型的結果,默認的,每一個接口都使用了[AutoReturn],除非給接口顯性地給方法配置了[XmlReturn]或[JsonResult]。若是以上返回的userStr是UserInfo類型的xml或json文本,那麼強類型的代碼聲明以下:web

[HttpHost("http://www.mywebapi.com")]
public interface MyWebApi : IDisposable
{
    // GET /webapi/user?account=laojiu
    [HttpGet("/webapi/user")]    
    ITask<UserInfo> GetUserByAccountAsync(string account);
}

[HttpHost("http://www.mywebapi.com")]
[JsonReturn] // 指明使用Json處理返回值爲UserInfo類型
public interface MyWebApi : IDisposable
{
    // GET /webapi/user?account=laojiu
    [HttpGet("/webapi/user")]    
    ITask<UserInfo> GetUserByAccountAsync(string account);
}

2.請求URL的多個參數

2.1 參數平鋪

你能夠將多個參數一一設計爲接口的參數,相似於:編程

// GET /webapi/user?account=laojiu&password=123456
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(string account, string password);

2.2 參數合併到模型

也能夠將全部參數合到一個簡單的多屬性模型對象:json

public class MyParameters
{
    public string Account { get; set; }
    public string Password { get; set; }         
}

// GET /webapi/user?account=laojiu&password=123456
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(MyParameters parameters);

2.3 模型+簡單參數混合

在一些場景中,除了提交多屬性模型對象以外,可能還須要一個簡單類型的額外參數,你能夠以下編寫接口:c#

// GET /webapi/user?account=laojiu&password=123456&birthDay=2010-01-01 01:01:01
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(MyParameters parameters,DateTime birthDay);

上面這裏,你可能會遇到一個問題,birthDay會簡單的ToString()值作爲參數值,若是你但願只須要日期而不包含時間,你能夠給birthDay指定格式:api

// GET /webapi/user?account=laojiu&password=123456&birthDay=2010-01-01
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(
    MyParameters parameters,
    [PathQuery("yyyy-MM-dd")] DateTime birthDay);

實際上,對於沒有任何特性修飾的每一個參數,都默認被[PathQuery]修飾,表示作爲請求路徑或請求參數處理,[PathQuery]的構造器重載方法能夠指定日期時間格式。服務器

3.設計一個Post請求接口

3.1使用x-www-form-urlencoded提交請求

// POST webapi/user  
// Body Account=laojiu&Password=123456
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync([FormContent] UserInfo user);

設計風格和Get請求是差很少的,你應該發現,接口參數被[FormContent]修飾了,[FormContent]的做用是將模型參數user以key1=value1&key2=value2的方式寫入到請求內容中。若是你還須要提供一個額外的簡單類型參數,須要使用[FormField]修飾這個參數,能夠這樣設計接口:app

// POST webapi/user  
// Body Account=laojiu&Password=123456&fieldX=xxx
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(
    [FormContent] UserInfo user, 
    [FormField] string fieldX);

3.2使用multipart/form-data提交請求

// POST webapi/user  
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithMulitpartAsync([MulitpartContent] UserInfo user);

// POST webapi/user  
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithMulitpartAsync(
    [MulitpartContent] UserInfo user, 
    [MulitpartText] string nickName,
    MulitpartFile file);

須要瞭解的是,[MulitpartText]表示是一個文本項,而MulitpartFile表示一個文件項,MulitpartFile實現了IApiParameterable接口,它不須要任何特性的修飾,它能提供自我解釋和處理。框架

3.3提交Json或Xml文本

對於json和xml,只能一次性提交一個參數,不支持額外參數之說

// POST webapi/user  
// Body user的json文本
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithJsonAsync([JsonContent] UserInfo user);

// POST webapi/user  
// Body user的xml文本
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithXmlAsync([XmlContent] UserInfo user);

若是你的UserInfo有DateTime類型的屬性,你可使用[JsonContent("時間格式")]來修飾接口參數,不然時間格式使用HttpApiConfig的DateTimeFormate。

3.4 提交原始的HttpContent

// POST webapi/user  
// Body Account=laojiu&Password=123456
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(FormUrlEncodedContent user);

// POST webapi/user  
// Body Account=laojiu&Password=123456&age=18
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(
    [HttpContent] FormUrlEncodedContent user,
    [FormField] int age);

默認的,全部System.Net.Http.HttpContent類型的參數,都會被[HttpContent]特性修飾,並且能夠與表單字段特性等混合使用。值得說明的話,傳統的System.Net.Http.HttpContent類型參數必須放到其它表單字段參數的前面。

4. 動態指定請求的域名或Url

4.1 域名動態而相對路徑固定

以上的例子,請求的根路徑都是硬編碼,而在很多場景中是放在配置文件中的,能夠在建立接口實例時建立配置項:

var config = new HttpApiConfig
{
    // 請求的域名,會覆蓋[HttpHost]特性
    HttpHost = new Uri("http://www.webapiclient.com"),
};
var myWebApi = HttpApiClient.Create<MyWebApi>(config);
var userStr = await myWebApi.GetUserByAccountAsync("laojiu");
myWebApi.Dispose();

4.2 每一個請求接口的URL路徑都是動態的

有時,多個接口方法的所有URL都是運行時才肯定的,這時,須要給每一個接口作以下的調整,注意[Url]特性表示參數是請求的URL,要求必須放在第一個參數。:

public interface MyWebApi : IDisposable
{
    // GET {URL}?account=laojiu
    [HttpGet]
    ITask<string> GetUserByAccountAsync([Url] string url, string account);
}

4.3 相對路徑某個分段動態

有時,有些接口會將某個參數作路徑的一個分段,好比GET http://www.webapiclient.com/{account},這裏的{account}是動態的,獲取哪一個帳號的資料就填寫哪一個帳號,能夠以下設計接口

public interface MyWebApi : IDisposable
{
    // GET http://www.webapiclient.com/laojiu
    [HttpGet("http://www.webapiclient.com/{account}"]
    ITask<string> GetUserByAccountAsync(string account);
}

5.參數別名或屬性別名

5.1 參數別名

有些服務端接口要求的鍵名與你的編程風格不一致,或者使用了特殊的鍵名爲.net語言不容許的參數名,你可使用[AliasAs("name")]來給參數或模型的屬性別名。

public interface MyWebApi : IDisposable
{
    // GET http://www.mywebapi.com/webapi/user?_name=laojiu
    [HttpGet("http://www.mywebapi.com/webapi/user")]
    ITask<string> GetUserByAccountAsync(
        [AliasAs("_name")] string account);
}

5.2 模型的屬性別名

public class UserInfo
{
    [AliasAs("loginAccount")]
    public string Account { get; set; }

    public string Password { get; set; }
}

6.特性的範圍和優先級

6.1 特性的範圍

有些特性好比[Header],能夠修飾於接口、方法和參數,使用不一樣的構造器和修飾於不一樣的地方產生的含義和結果是有點差異的:

  • 修飾接口時,表示接口下的全部方法在請求前都會添加這個請求頭;
  • 修飾方法時,表示此方法在語法前添加這個請求頭;
  • 修飾參數時,表示參數的值將作爲請求頭的值,由調用者動態傳入;

6.2 特性的優先級

有些特性好比[AutoReturn]和[JsonReturn],能夠修飾於接口和方法,但特性的AllowMultiple爲false,若是在接口級生明方法級[AutoReturn],在方法級上聲明[JsonReturn],此方法實際生效的是[JsonReturn];再好比[Timeout]特性,若是在接口級聲明[Timeout(5000)]在方法級聲明[Timeout(10000)],實際生效的是[Timeout(10000)],總結以下:

  • AllowMultiple爲false的同一個特性,方法級比接口級優先級高
  • AllowMultiple爲false的不一樣類型的[ReturnAttribute],方法級比接口級優先級高
相關文章
相關標籤/搜索