在現代 Web 應用程序中,調用第三方 Web API 來增強應用程序的功能是很常見的。有數以千計的免費和商業 API 可用,如果您知道如何在 ASP.NET Core 應用程序中使用這些 API,您就可以構建非常強大的業務應用程序。在這篇文章中,我將解釋如何在 ASP.NET Core 應用程序中使用第三方 Web API。
第三方 API 概覽
我們將開發一個允許用戶輸入國家代碼和年份的應用程序,然后我們將調用第三方 API 來獲取該特定國家在該特定年份的公共假期列表。我們將使用的第三方 API 稱為 Nager.Date,這是一個全球公共假期 API。
這是一個非常簡單的 API,您可以通過輸入以下 URL 在 Postman 中輕松測試此 API。
https://date.nager.at/api/v2/PublicHolidays/2020/US
該 API 的響應是 JSON 格式的公共假期列表,如下所示:
了解 HttpClient 對象
允許我們在 ASP.NET Core 應用程序中使用第三方 API 的最常見和眾所周知的類是 HttpClient 類。此類使我們能夠向第三方 API 發送 HTTP 請求並接收從這些 API 返回的 HTTP 響應。 HttpClient 的每個實例都維護着自己的連接池,這使得它可以將自己的請求與其他 HttpClient 實例執行的請求隔離開來。此類還充當更特定 HTTP 客戶端的基類。例如,您可以創建 FacebookHttpClient 或 TwitterHttpClient 作為基本 HttpClient 的子類,並且可以使用這些特定的 HTTP 客戶端與 Facebook 和 Twitter API 進行通信。
建議創建一個 HttpClient 實例並在整個應用程序生命周期中重復使用它。這是因為為每個請求實例化一個新的 HttpClient 實例很容易耗盡重負載下可用的套接字數量。這主要是因為當 HttpClient 對象被釋放,底層套接字不會立即釋放。 您可以閱讀這篇精彩的博客文章您使用 HttpClient 錯誤,這會破壞您的軟件的穩定性,以獲取有關我剛剛提到的問題的更多信息。
在 ASP.NET Core 中使用 HttpClient
正如我上面提到的,我們將創建一個應用程序,允許用戶查看任何國家/地區的公共假期列表。讓我們創建一個 ASP.NET Core MVC Web 應用程序並創建以下接口。這個接口只有一個 GetHolidays 方法,它有兩個參數 countryCode 和 year,我們很快就會從用戶那里收到。
public interface IHolidaysApiService
{
Task<List<HolidayModel>> GetHolidays(string countryCode, int year);
}
上面的 GetHolidays 方法返回一個 HolidayModel 列表,它是一個模型類,具有與 Nager.Date API 的響應映射的屬性。
public class HolidayModel
{
public string Name { get; set; }
public string LocalName { get; set; }
public DateTime? Date { get; set; }
public string CountryCode { get; set; }
public bool Global { get; set; }
}
接下來,我們需要實現一個 HolidaysApiService 類,該類將實現上面聲明的 IHolidaysApiService。請注意我是如何在類中聲明私有和靜態 HttpClient 變量的,以及它是如何在類的靜態構造函數中定義的。這是 Microsoft 官方文檔中提到的創建 HttpClient 實例的推薦方法。
public class HolidaysApiService : IHolidaysApiService
{
private static readonly HttpClient client;
static HolidaysApiService()
{
client = new HttpClient()
{
BaseAddress = new Uri("https://date.nager.at")
};
}
}
接下來我們需要定義 GetHolidays 方法,如下所示:
public async Task<List<HolidayModel>> GetHolidays(string countryCode, int year)
{
var url = string.Format("/api/v2/PublicHolidays/{0}/{1}", year, countryCode);
var result = new List<HolidayModel>();
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var stringResponse = await response.Content.ReadAsStringAsync();
result = JsonSerializer.Deserialize<List<HolidayModel>>(stringResponse,
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
}
else
{
throw new HttpRequestException(response.ReasonPhrase);
}
return result;
}
上面的方法發生了很多事情,所以讓我詳細解釋一下:
- 第一行是構建 Nager.Date API 的 URL 並使用 year 和 countryCode 參數
var url = string.Format("/api/v2/PublicHolidays/{0}/{1}", year, countryCode);
- 接下來,我們將使用 GetAsync 方法進行 API 調用,該方法將 GET 請求作為異步操作發送到指定的 Uri。該方法返回 System.Net.Http.HttpResponseMessage 對象,該對象表示包含狀態代碼和數據的 HTTP 響應消息。
var response = await client.GetAsync(url);
- 接下來,我們調用 ReadAsStringAsync 方法將 HTTP 內容序列化為字符串
var stringResponse = await response.Content.ReadAsStringAsync();
- 最后,我們使用 JsonSerializer 將 JSON 響應字符串反序列化為 HolidayModel 對象列表。
result = JsonSerializer.Deserialize<List<HolidayModel>>(stringResponse,
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
這就是我們使用第三方公共假期 API 所需的全部內容。要使用我們的 HolidaysApiService,我們需要首先在 Startup.cs 類中注冊我們的服務。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<IHolidaysApiService, HolidaysApiService>();
}
接下來,我們可以在 HomeController 中注入我們的 HolidaysApiService 並通過傳遞我們將在 Index action 方法中接收的 countryCode 和 year 參數來調用 GetHolidays 方法。
public class HomeController : Controller
{
private readonly IHolidaysApiService _holidaysApiService;
public HomeController(IHolidaysApiService holidaysApiService)
{
_holidaysApiService = holidaysApiService;
}
public async Task<IActionResult> Index(string countryCode, int year)
{
List<HolidayModel> holidays = new List<HolidayModel>();
holidays = await _holidaysApiService.GetHolidays(countryCode, year);
return View(holidays);
}
}
最后,我們需要一個 Razor 視圖來創建一個表單,用戶將在其中輸入國家代碼和年份。表單將提交給上述 Index 操作,然后該操作將調用 GetHolidays 方法。這是 Index.cshtml Razor 視圖的代碼,顯示了一個 HTML 表單和一個用於顯示公共假期的表格。
@model List<HolidayModel>
@{
ViewData["Title"] = "Home Page";
}
<div>
<h3 class="display-4">Public Holidays Finder</h3>
<center>
<form asp-controller="Home" asp-action="Index">
<table>
<tr>
<td>Country Code: </td>
<td><input type="text" id="txtCountryCode" name="CountryCode" /></td>
<td>Year: </td>
<td><input type="text" id="txtYear" name="Year" /></td>
<td><input type="submit" value="Submit" /></td>
</tr>
</table>
<hr />
</form>
</center>
@if (Model != null && Model.Count > 0)
{
<table class="table table-bordered table-striped table-sm">
<thead>
<tr>
<th>Date</th>
<th>Name</th>
<th>Local Name</th>
<th>Country Code</th>
<th>Global</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.Date.Value.ToShortDateString()</td>
<td>@Html.DisplayFor(modelItem => item.Name)</td>
<td>@Html.DisplayFor(modelItem => item.LocalName)</td>
<td>@Html.DisplayFor(modelItem => item.CountryCode)</td>
<td>@Html.DisplayFor(modelItem => item.Global)</td>
</tr>
}
</tbody>
</table>
}
</div>
現在是時候測試我們的應用程序,看看我們是否能夠使用第三方 API。在 Visual Studio 中按 F5,您將看到類似於以下內容的頁面。您可以輸入國家代碼,例如美國、德國等,以及一年,例如2021,然后單擊“提交”按鈕,如果一切順利,您將看到我們的代碼調用第三方 API,從 API 中獲取公共假期列表並將其顯示在頁面上。
使用 IHttpClientFactory 管理 HttpClient 對象
為了使 HttpClient 實例易於管理,並避免上述套接字耗盡問題,.NET Core 2.1 引入了 IHttpClientFactory 接口,可用於通過依賴注入 (DI) 在應用程序中配置和創建 HttpClient 實例。為了使用 IHttpClientFactory,我們可以通過調用 AddHttpClient(IServiceCollection) 在 Startup.cs 文件中注冊它。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<IHolidaysApiService, HolidaysApiService>();
services.AddHttpClient("PublicHolidaysApi", c => c.BaseAddress = new Uri("https://date.nager.at"));
}
可以使用 AddHttpClient 方法注冊多個具有不同名稱的 HTTP 客戶端。 AddHttpClient 方法的第一個參數是客戶端的名稱,第二個參數是將配置 HttpClient 的 Lamba 表達式。在上面的示例中,我使用要使用此特定 HTTP 客戶端調用的第三方 API 的 URL 來設置 BaseAddress 屬性。
一旦 HTTP 客戶端被注冊,我們就可以在我們的控制器和服務中注入 IHttpClientFactory 並調用它的 CreateClient 方法來創建我們想要在我們的代碼中使用的特定 HTTP 客戶端對象。 CreateClient 方法需要您要創建的 HTTP 客戶端的名稱,如下所示:
public class HolidaysApiService : IHolidaysApiService
{
private readonly HttpClient client;
public HolidaysApiService(IHttpClientFactory clientFactory)
{
client = clientFactory.CreateClient("PublicHolidaysApi");
}
public async Task<List<HolidayModel>> GetHolidays(string countryCode, int year)
{
var url = string.Format("/api/v2/PublicHolidays/{0}/{1}", year, countryCode);
var result = new List<HolidayModel>();
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var stringResponse = await response.Content.ReadAsStringAsync();
result = JsonSerializer.Deserialize<List<HolidayModel>>(stringResponse,
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
}
else
{
throw new HttpRequestException(response.ReasonPhrase);
}
return result;
}
}
總結概括
在本文中,我向您概述了 HttpClient,並提供了直接或使用 IHttpClientFactory 創建 HttpClient 對象的示例。我還向您展示了一個使用 HttpClient 調用第三方 Web API 的示例。希望您現在熟悉 HttpClient 對象及其用法,並且可以放心地開始在您的項目中使用它。