在ASP.NET Core中應(yīng)用HttpClient獲取數(shù)據(jù)和內(nèi)容
在本文中,我們將學(xué)習(xí)如何在ASP.NET Core中集成和使用HttpClient。在學(xué)習(xí)不同HttpClient功能的同時(shí)使用Web API的資源。如何從Web API獲取數(shù)據(jù),以及如何直接使用HttpRequestMessage類來(lái)實(shí)現(xiàn)這些功能。在以后的文章中,我們將學(xué)習(xí)如何發(fā)送POST、PUT和DELETE請(qǐng)求,以及如何使用HttpClient發(fā)送PATCH請(qǐng)求。
要下載源代碼,可以訪問(wèn)https://github.com/CodeMazeBlog/httpclient-aspnetcore/tree/fetching-data-with-httpclient以獲取項(xiàng)目。
概述
如果你打開HttpClient存儲(chǔ)庫(kù)的主分支,您將發(fā)現(xiàn)兩個(gè)項(xiàng)目:CompanyEmployees和CompanyEmployees. client。第一個(gè)項(xiàng)目是ASP.NET Core Web API項(xiàng)目,它將是本教程的服務(wù)器端項(xiàng)目。它由幾個(gè)項(xiàng)目組成:
API項(xiàng)目對(duì)于我們的文章和整個(gè)系列來(lái)說(shuō)也不是最重要的。重要的是它使用SQL數(shù)據(jù)庫(kù),所以你需要做的就是修改appsettings中的連接字符串。然后運(yùn)行Update-Migration命令。所有需要的數(shù)據(jù)都將被遷移到數(shù)據(jù)庫(kù)中。
然后,還有客戶端應(yīng)用程序——ASP.NET Core控制臺(tái)應(yīng)用程序。它有一個(gè)單獨(dú)的服務(wù)HttpClientCrudService,我們將在本文中修改它,一個(gè)單獨(dú)的接口IHttpClientServiceImplementation,所有HttpClient服務(wù)都將從它繼承,數(shù)據(jù)傳輸類和一個(gè)修改過(guò)的Program類:
讓我們來(lái)看看Program類的當(dāng)前代碼
class Program { static async Task Main(string[] args) { var services = new ServiceCollection(); ConfigureServices(services); var provider = services.BuildServiceProvider(); try { await provider.GetRequiredService<IHttpClientServiceImplementation>() .Execute(); } catch (Exception ex) { Console.WriteLine($"Something went wrong: {ex}"); } } private static void ConfigureServices(IServiceCollection services) { services.AddScoped<IHttpClientServiceImplementation, HttpClientCrudService>(); } }
這沒(méi)有什么特別的。我們準(zhǔn)備服務(wù)集合,將服務(wù)添加到IOC中,并從服務(wù)中執(zhí)行默認(rèn)方法。當(dāng)我們?cè)谡麄€(gè)教程中添加不同的服務(wù)時(shí),我們將擴(kuò)展ConfigureServices方法。
關(guān)于HttpClient
我們不會(huì)深入研究關(guān)于HttpClient的理論,因?yàn)槲覀儗氖纠袑W(xué)到很多東西,但是讓我們看看一些基礎(chǔ)知識(shí)。
HttpClient是一個(gè)類,它允許我們發(fā)送HTTP請(qǐng)求,并從指定URI接收HTTP響應(yīng)。我們可以使用這個(gè)類發(fā)送各種HTTP請(qǐng)求,如GET、POST、PUT、DELETE、PATCH并來(lái)自服務(wù)器的響應(yīng)。
HttpClient使用HTTP消息處理程序發(fā)送請(qǐng)求并獲取響應(yīng)。這是默認(rèn)消息處理程序的主要工作。如果我們閱讀微軟的文檔,我們會(huì)讀到.NET Framework和.NET Core 2.0以及更早版本的默認(rèn)是HttpClientHander。但是在.NET Core 2.1和更高版本中,默認(rèn)的是SocketsHttpHandler。
但是,HttpClient不只是使用一個(gè)消息處理程序。我們可以附加多個(gè)消息處理程序并創(chuàng)建管道。有些處理程序只能操作請(qǐng)求的頭,有些可以處理超時(shí),等等。
在ASP.NET Core中使用HttpClient發(fā)送GET請(qǐng)求
現(xiàn)在,讓我們從修改HttpClientCrudService 類開始:
public class HttpClientCrudService : IHttpClientServiceImplementation { private static readonly HttpClient _httpClient = new HttpClient(); public HttpClientCrudService() { _httpClient.BaseAddress = new Uri("https://localhost:5001/api/"); _httpClient.Timeout = new TimeSpan(0, 0, 30); } public async Task Execute() { } }
這里,我們創(chuàng)建了一個(gè)HttpClient屬性,初始化它,并在構(gòu)造函數(shù)中進(jìn)行配置,我們?cè)O(shè)置了API的URI及超時(shí)時(shí)間。當(dāng)然,我們可以在這個(gè)配置中找到更多的屬性來(lái)使用,但是現(xiàn)在,這就足夠了。稍后,當(dāng)我們開始學(xué)習(xí)HttpClientFactory時(shí),我們將把這些配置移到別的地方。
現(xiàn)在,我們可以在這個(gè)類中添加一個(gè)新方法:
public async Task GetCompanies() { var response = await _httpClient.GetAsync("companies"); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); var companies = JsonSerializer.Deserialize<List<CompanyDto>>(content, _options); }
在這個(gè)方法中,我們使用HttpClient中的GetAsync方法,并傳入地址。為了確保響應(yīng)是成功的,我們調(diào)用EnsureSuccessStatusCode方法。一旦確定有成功狀態(tài)碼的響應(yīng),就可以將響應(yīng)的內(nèi)容作為字符串讀取。最后,我們對(duì)數(shù)據(jù)列表進(jìn)行反序列化。如你所見(jiàn),我們使用了一個(gè)JsonSerializerOptions類型的參數(shù),所以讓我們將它添加到我們的類中,并在Execute方法中調(diào)用這個(gè)方法:
private readonly JsonSerializerOptions _options; public HttpClientCrudService() { _httpClient.BaseAddress = new Uri("https://localhost:5001/api/"); _httpClient.Timeout = new TimeSpan(0, 0, 30); _options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; } public async Task Execute() { await GetCompanies(); }
我們?yōu)镴sonSerializer設(shè)置不區(qū)分大小寫的反序列化選項(xiàng)。沒(méi)有它,我們的響應(yīng)就不會(huì)被正確地反序列化。
現(xiàn)在,我們可以在GetCompanies方法中添加一個(gè)斷點(diǎn),啟動(dòng)Web API項(xiàng)目,然后啟動(dòng)客戶端:
正如我們所看到的,我們?cè)赾ompanies變量中得到了結(jié)果。
支持不同的響應(yīng)格式
在本例中,我們接收到一個(gè)JSON作為默認(rèn)的響應(yīng)格式。我們的API默認(rèn)支持這種類型。但有些API不默認(rèn)為JSON,它們可能支持XML作為默認(rèn)的響應(yīng)格式或任何其他格式。在這種情況下,我們的邏輯就行不通了。
除了JSON之外,我們的API還支持XML響應(yīng)格式。讓我們看看如何在客戶端應(yīng)用程序中明確地要求格式。
首先,Http請(qǐng)求和響應(yīng)都包含一組頭,我們可以使用這些頭在客戶端和服務(wù)器應(yīng)用程序之間傳遞附加信息。HTTP請(qǐng)求的通用頭是Accept。我們使用這個(gè)頭告訴服務(wù)器客戶端將接受哪種媒體類型:accept: application/json, text/xml。
所以,讓我們看看如何在我們的請(qǐng)求中設(shè)置頭:
public HttpClientCrudService() { _httpClient.BaseAddress = new Uri("https://localhost:5001/api/"); _httpClient.Timeout = new TimeSpan(0, 0, 30); _httpClient.DefaultRequestHeaders.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("text/xml")); _options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; }
這里,我們使用DefaultRequestHeaders屬性并將其清除。然后,我們使用Accept屬性,由于它是一個(gè)集合,所以我們添加了兩個(gè)MediaTypeWithQualityHeaderValue對(duì)象。對(duì)于第一個(gè)對(duì)象,我們支持JSON格式,對(duì)于第二個(gè)對(duì)象,我們支持XML格式。為此,我們需要添加一個(gè)新的using語(yǔ)句:
using System.Net.Http.Headers;
現(xiàn)在,如果有一個(gè)像這樣的配置,必須在方法中添加一些額外的代碼,以決定如何反序列化響應(yīng):
public async Task GetCompanies() { var response = await _httpClient.GetAsync("companies"); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); var companies = new List<CompanyDto>(); if(response.Content.Headers.ContentType.MediaType == "application/json") { companies = JsonSerializer.Deserialize<List<CompanyDto>>(content, _options); } else if(response.Content.Headers.ContentType.MediaType == "text/xml") { var doc = XDocument.Parse(content); foreach (var element in doc.Descendants()) { element.Attributes().Where(a => a.IsNamespaceDeclaration).Remove(); element.Name = element.Name.LocalName; } var serializer = new XmlSerializer(typeof(List<CompanyDto>)); companies = (List<CompanyDto>)serializer.Deserialize(new StringReader(doc.ToString())); } }
由于我們同時(shí)支持JSON和XML格式,我們必須檢查哪個(gè)ContentType被應(yīng)用到響應(yīng)。如果是JSON,我們只需執(zhí)行標(biāo)準(zhǔn)的反序列化。但如果是XML,我們將內(nèi)容解析為XDocument。最后,我們創(chuàng)建一個(gè)新的XmlSerializer并反序列化XDocument。
此時(shí),如果我們啟動(dòng)兩個(gè)應(yīng)用程序,并在方法中放置一個(gè)斷點(diǎn),我們將看到我們的默認(rèn)格式是JSON:
HttpClient中的優(yōu)先級(jí)
在我們的Accept頭設(shè)置中,我們支持兩種具有相同優(yōu)先級(jí)的格式。優(yōu)先級(jí)的最大值為1。但是,我們可以為這兩個(gè)頭文件中的一個(gè)設(shè)置較低的首選項(xiàng)——值必須在0到1之間。有較高值的請(qǐng)求將有更高優(yōu)先級(jí)。
所以,讓我們?cè)跇?gòu)造函數(shù)中降低JSON Accept頭的優(yōu)先級(jí):
_httpClient.DefaultRequestHeaders.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json", 0.9)); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("text/xml"));
正如我們所看到的,MediaTypeWithQualityHeaderValue構(gòu)造函數(shù)接受另一個(gè)參數(shù)。我們將它的值設(shè)置為0.9。因?yàn)槲覀儧](méi)有為XML Accept頭添加任何值,所以默認(rèn)值是1?,F(xiàn)在,如果我們開始我們的應(yīng)用程序,我們會(huì)發(fā)現(xiàn)XML是優(yōu)先級(jí)更高的格式:
因此,執(zhí)行將跳過(guò)這一部分并執(zhí)行我們的XML反序列化。讓我們?cè)赬Document解析之前檢查響應(yīng)體:
然后,讓我們?cè)诮馕霾僮髦髾z查doc變量:
我們可以看出區(qū)別。在解析操作之后,反序列化就成功完成了:
我們已經(jīng)看到了如何在請(qǐng)求中向HTTP Accept頭添加首選項(xiàng)。但現(xiàn)在問(wèn)題出現(xiàn)了。如果我們使用部分請(qǐng)求頭,該怎么辦?
使用HttpRequestMessage類發(fā)送HTTP請(qǐng)求
在這個(gè)實(shí)現(xiàn)中,我們對(duì)每個(gè)請(qǐng)求使用相同的頭配置。因此,如果想發(fā)送默認(rèn)為JSON格式的HTTP請(qǐng)求,我們不能使用這個(gè)類中的HTTP配置來(lái)實(shí)現(xiàn)。這是因?yàn)槲覀儗ML格式設(shè)置為默認(rèn)格式。這意味著我們必須提供一個(gè)不同的解決方案。
如果我們仔細(xì)考慮這一點(diǎn),我們可以得出結(jié)論:BaseAddress和Timeout屬性與HttpClient相關(guān),但Accept頭的屬性連接到請(qǐng)求本身。同樣,當(dāng)我們使用GetAsync方法時(shí),它在內(nèi)部使用GET HTTP方法創(chuàng)建了一個(gè)新的HttpRequestMessage。也就是說(shuō),我們可以創(chuàng)建自己的HttpRequestMessage并為該請(qǐng)求提供報(bào)頭。
最佳實(shí)踐是在HttpClient實(shí)例上設(shè)置默認(rèn)配置,在HTTP請(qǐng)求本身上設(shè)置請(qǐng)求配置。當(dāng)然,如果我們總是希望使用JSON格式作為Accept報(bào)頭,我們可以在HttpClient設(shè)置它。
實(shí)現(xiàn)
現(xiàn)在,讓我們看看如何使用HttpRequestMessage類來(lái)實(shí)現(xiàn)HTTP請(qǐng)求。
首先,讓我們從構(gòu)造函數(shù)中移除accept頭文件的配置:
public HttpClientCrudService() { _httpClient.BaseAddress = new Uri("https://localhost:5001/api/"); _httpClient.Timeout = new TimeSpan(0, 0, 30); _httpClient.DefaultRequestHeaders.Clear(); _options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; }
然后,我們可以將GetCompanies方法恢復(fù)到之前:
public async Task GetCompanies() { var response = await _httpClient.GetAsync("companies"); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); var companies = JsonSerializer.Deserialize<List<CompanyDto>>(content, _options); }
最后,我們可以添加新方法:
public async Task GetCompaniesWithXMLHeader() { var request = new HttpRequestMessage(HttpMethod.Get, "companies"); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml")); var response = await _httpClient.SendAsync(request); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); var doc = XDocument.Parse(content); foreach (var element in doc.Descendants()) { element.Attributes().Where(a => a.IsNamespaceDeclaration).Remove(); element.Name = element.Name.LocalName; } var serializer = new XmlSerializer(typeof(List<CompanyDto>)); var companies = (List<CompanyDto>)serializer.Deserialize(new StringReader(doc.ToString())); }
因此,我們使用HttpRequestMessage類創(chuàng)建了一個(gè)新請(qǐng)求,該類提供了HTTP Method作為參數(shù)和API的地址。然后,向請(qǐng)求添加報(bào)頭,并調(diào)用SendAsync方法發(fā)送請(qǐng)求。提取內(nèi)容之后,重復(fù)前面方法中所做的步驟。我們還要做最后一件事。
讓我們確保一旦客戶端應(yīng)用程序啟動(dòng),這個(gè)方法就會(huì)被調(diào)用:
public async Task Execute(){ //await GetCompanies(); await GetCompaniesWithXMLHeader();}
正如我們之前所做的,我們將在這個(gè)方法中放置一個(gè)斷點(diǎn)并啟動(dòng)兩個(gè)應(yīng)用程序:
如你所見(jiàn),我們得到的結(jié)果與前面相同,但這次我們使用HttpRequestMessage的單獨(dú)方法發(fā)送帶有XML Accept頭的HTTP請(qǐng)求。
結(jié)論
在本文中,我們討論了HttpClient,以及如何在我們的ASP.NET Core中使用它處理來(lái)自Web API的數(shù)據(jù)。
原文鏈接:https://code-maze.com/fetching-data-with-httpclient-in-aspnetcore/
以上就是在ASP.NET Core中集成和使用HttpClient獲取數(shù)據(jù)和內(nèi)容的詳細(xì)內(nèi)容,更多關(guān)于ASP.NET Core中集成和使用HttpClient的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- ASP.NET Core擴(kuò)展庫(kù)之Http通用擴(kuò)展庫(kù)的使用詳解
- ASP.NET Core擴(kuò)展庫(kù)之Http日志的使用詳解
- 如何在ASP.NET Core中使用HttpClientFactory
- 在ASP.NET Core中用HttpClient發(fā)送POST, PUT和DELETE請(qǐng)求
- 在ASP.NET Core5.0中訪問(wèn)HttpContext的方法步驟
- .NET CORE HttpClient的使用方法
- ASP.NET Core中的Http緩存使用
- .net Core 使用IHttpClientFactory請(qǐng)求實(shí)現(xiàn)
- .NET Core使用HttpClient進(jìn)行表單提交時(shí)遇到的問(wèn)題
- .Net Core下HTTP請(qǐng)求IHttpClientFactory示例詳解
- 如何在 .NET 中使用 Flurl 高效處理Http請(qǐng)求
相關(guān)文章
基于.NET的FluentValidation數(shù)據(jù)驗(yàn)證實(shí)現(xiàn)
這篇文章主要介紹了基于.NET的FluentValidation數(shù)據(jù)驗(yàn)證實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11ASP.NET Core MVC 中實(shí)現(xiàn)中英文切換的示例代碼
這篇文章主要介紹了ASP.NET Core MVC 中實(shí)現(xiàn)中英文切換的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02基于.Net?Core認(rèn)證授權(quán)方案之JwtBearer認(rèn)證
這篇文章介紹了基于.Net?Core認(rèn)證授權(quán)方案之JwtBearer認(rèn)證,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06ASP.NET學(xué)習(xí)CORE中使用Cookie身份認(rèn)證方法
本篇文章主要給大家詳細(xì)分析了ASP.NET學(xué)習(xí)CORE中使用Cookie身份認(rèn)證方法以及相關(guān)的實(shí)例代碼,有需要的朋友參考下吧。2018-01-01asp.net使用WebAPI和EF框架結(jié)合實(shí)現(xiàn)數(shù)據(jù)的基本操作
這篇文章介紹了asp.net使用WebAPI和EF框架結(jié)合實(shí)現(xiàn)數(shù)據(jù)基本操作的案例,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04