聲名式服務調用,己經不算是一個新鮮的話題了,畢竟都出來好些年了。react
下面談談,最近項目中用到一個這樣的組件的簡單實踐。git
目前部分項目用到的是Refit這個組件,都是配合HttpClientFactory來使用的。github
關於HttpClientFactory的一些簡單介紹,能夠參見官方文檔,也能夠看看前面的兩篇比較粗略的相關介紹。json
也簡單介紹一下背景,目前主要有兩類的API接口:api
第一類是註冊到Eureka中的,能夠經過服務發現的方式來請求的,這裏的都是新的接口。安全
第二類是原始的接口,不能走服務發現,只能經過直連請求的方式來調用,這裏的都是些老接口。服務器
換句話就是說,要同時兼容這兩類接口。網絡
因爲用HttpClientFactory集成服務發現十分簡單,因此優先選了一個自己就帶有HttpClientFactory的組件--Refit。架構
Refit是一個自動類型安全的REST庫,是RESTful架構的.NET客戶端實現,app
它基於Attribute,提供了把REST API返回的數據轉化爲(Plain Ordinary C# Object,簡單C#對象),POCO to JSON,網絡請求(POST,GET,PUT,DELETE等)封裝,內部封裝使用HttpClient,前者專一於接口的封裝,後者專一於網絡請求的高效,兩者分工協做。
咱們的應用程序經過 refit請求網絡,其實是使用 refit接口層封裝請求參數、Header、Url 等信息,以後由 HttpClient完成後續的請求操做,在服務端返回數據以後,HttpClient將原始的結果交給 refit,後者根據用戶的需求對結果進行解析的過程。
更多細節能夠參考Refit的官網
直接上控制器的代碼了〜〜
// GET: api/persons [HttpGet] public IEnumerable<Person> Get() { return new List<Person> { new Person{Id = 1 , Name = "catcher wong", CreateTime = DateTime.Now}, new Person{Id = 2 , Name = "james li", CreateTime = DateTime.Now.AddDays(-2)} }; } // GET api/persons/5 [HttpGet("{id}")] public Person Get(int id) { return new Person { Id = id, Name = "name" }; } // POST api/persons [HttpPost] public Person Post([FromBody]Person person) { if (person == null) return new Person(); return new Person { Id = person.Id, Name = person.Name }; } // PUT api/persons/5 [HttpPut] public string Put([FromBody]int id) { return $"put {id}"; } // DELETE api/persons/5 [HttpDelete("{id}")] public string Delete(int id) { return $"del {id}"; }
先經過Nuget安裝Refit的包。
而後就是定義咱們的interface了
public interface IPersonsApi { [Get("/api/persons")] Task<List<Person>> GetPersonsAsync(); [Get("/api/persons/{id}")] Task<Person> GetPersonAsync([AliasAs("id")]int personId); [Post("/api/persons")] Task<Person> AddPersonAsync([Body]Person person); [Put("/api/persons")] Task<string> EditPersonAsync([Body]int id); [Delete("/api/persons/{id}")] Task<string> DeletePersonAsync(int id); }
來看看這個interface裏面涉及到的部份內容。
而後是配合HttpClientFactory
再經過Nuget安裝一下Refit.HttpClientFactory
若是PersonApi是註冊到Euerka的,能夠再添加Steeltoe的引用。
public void ConfigureServices(IServiceCollection services) { services.AddRefitClient<IPersonsApi>() .ConfigureHttpClient(options => { options.BaseAddress = new Uri(Configuration.GetValue<string>("personapi_url")); //other settings of httpclient }) //Steeltoe discovery //.AddHttpMessageHandler<DiscoveryHttpMessageHandler>() ; services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
前面在定義IPersonApi的時候,咱們只指定了相對路徑,而請求IP並無指定,這裏是放到ConfigureHttpClient裏面去指定了。
同時根據不一樣環境,配置不一樣的appsettings.{env}.json,達到切換的效果。
一樣的,若是想走服務發現,只須要放開註釋的AddHttpMessageHandler,同時修改BaseeAddress爲服務名的形式就能夠了。
說了這麼多,都還只是配置階段,下面就來看看具體怎麼用。
爲了演示方便,就不在建一個Service層了,直接在控制器調用一下。
用法也很簡單,直接在控制器注入一下就可使用了。
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly IPersonsApi _api; public ValuesController(IPersonsApi api) { this._api = api; } // GET api/values [HttpGet] public async Task<List<Person>> GetAsync() { return await _api.GetPersonsAsync(); } // GET api/values/5 [HttpGet("{id}")] public async Task<Person> Get(int id) { return await _api.GetPersonAsync(id); } // POST api/values [HttpPost] public async Task<Person> Post([FromBody] Person value) { return await _api.AddPersonAsync(value); } }
到這裏,代碼層面的東西已經處理完了。
下面來看看使用Refit效果(這裏只看兩個Get請求的):
都是能正常拿到咱們指望的結果。
最後再看看輸出的日誌,確認一下。
首先是訪問/api/values
的
確確實實是向咱們前面的PersonApi發起了請求。
而後是訪問/api/values/5555
的
可見咱們上面的別名(AliasAs)是起了效果的,能拼成正確的請求地址。
至於其餘類型的請求,這裏就不演示了,讓你們本身去嘗試一下吧。
Refit用起來仍是比較簡單的,運行了一段時間也還表現正常!
固然本文介紹的也只是一些基本的用法!它還具備不錯的擴展性,可讓咱們根據自身需求作一些定製化的東西。
本文的示例代碼RefitClientApi