從 .NET 用戶端呼叫 Web API (C#)
此內容適用于舊版 .NET。 新的開發應該使用ASP.NET Core。 如需使用 ASP.NET Core Web API 的詳細資訊,請參閱:
本教學課程說明如何使用System.Net.Http.HttpClient從 .NET 應用程式呼叫 Web API。
在本教學課程中,會撰寫取用下列 Web API 的用戶端應用程式:
動作 | HTTP method | 相對 URI |
---|---|---|
依照識別碼取得產品 | GET | /api/products/id |
建立新的產品 | POST | /api/products |
更新產品 | PUT | /api/products/id |
刪除產品 | 刪除 | /api/products/id |
若要瞭解如何使用 ASP.NET Web API實作此 API,請參閱建立支援 CRUD 作業的 Web API。
為了簡單起見,本教學課程中的用戶端應用程式是 Windows 主控台應用程式。 Windows Phone和 Windows 市集應用程式也支援HttpClient。 如需詳細資訊,請參閱 使用可攜式程式庫撰寫多個平臺的 Web API 用戶端程式代碼
注意: 如果您以硬式編碼值的形式傳遞基底 URL 和相對 URI,請留意使用 HttpClient
API 的規則。 屬性 HttpClient.BaseAddress
應設定為結尾斜線 (/
) 位址。 例如,將硬式編碼的資源 URI 傳遞至 HttpClient.GetAsync
方法時,請勿包含前置斜線。 若要依識別碼取得 Product
:
- 設置
client.BaseAddress = new Uri("https://localhost:5001/");
Product
要求 。 例如:client.GetAsync<Product>("api/products/4");
。
建立主控台應用程式
在 Visual Studio 中,建立名為 HttpClientSample 的新 Windows 主控台應用程式,並貼上下列程式碼:
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace HttpClientSample
{
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
class Program
{
static HttpClient client = new HttpClient();
static void ShowProduct(Product product)
{
Console.WriteLine($"Name: {product.Name}\tPrice: " +
$"{product.Price}\tCategory: {product.Category}");
}
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync(
"api/products", product);
response.EnsureSuccessStatusCode();
// return URI of the created resource.
return response.Headers.Location;
}
static async Task<Product> GetProductAsync(string path)
{
Product product = null;
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product;
}
static async Task<Product> UpdateProductAsync(Product product)
{
HttpResponseMessage response = await client.PutAsJsonAsync(
$"api/products/{product.Id}", product);
response.EnsureSuccessStatusCode();
// Deserialize the updated product from the response body.
product = await response.Content.ReadAsAsync<Product>();
return product;
}
static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
HttpResponseMessage response = await client.DeleteAsync(
$"api/products/{id}");
return response.StatusCode;
}
static void Main()
{
RunAsync().GetAwaiter().GetResult();
}
static async Task RunAsync()
{
// Update port # in the following line.
client.BaseAddress = new Uri("http://localhost:64195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try
{
// Create a new product
Product product = new Product
{
Name = "Gizmo",
Price = 100,
Category = "Widgets"
};
var url = await CreateProductAsync(product);
Console.WriteLine($"Created at {url}");
// Get the product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Update the product
Console.WriteLine("Updating price...");
product.Price = 80;
await UpdateProductAsync(product);
// Get the updated product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Delete the product
var statusCode = await DeleteProductAsync(product.Id);
Console.WriteLine($"Deleted (HTTP Status = {(int)statusCode})");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
}
}
上述程式碼是完整的用戶端應用程式。
RunAsync
會執行 和 封鎖,直到完成為止。 大部分 的 HttpClient 方法是非同步方法,因為它們會執行網路 I/O。 所有非同步工作都是在 內 RunAsync
完成。 應用程式通常不會封鎖主執行緒,但此應用程式不允許任何互動。
static async Task RunAsync()
{
// Update port # in the following line.
client.BaseAddress = new Uri("http://localhost:64195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try
{
// Create a new product
Product product = new Product
{
Name = "Gizmo",
Price = 100,
Category = "Widgets"
};
var url = await CreateProductAsync(product);
Console.WriteLine($"Created at {url}");
// Get the product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Update the product
Console.WriteLine("Updating price...");
product.Price = 80;
await UpdateProductAsync(product);
// Get the updated product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Delete the product
var statusCode = await DeleteProductAsync(product.Id);
Console.WriteLine($"Deleted (HTTP Status = {(int)statusCode})");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
安裝 Web API 用戶端程式庫
使用 NuGet 套件管理員來安裝 Web API 用戶端程式庫套件。
從 [工具] 功能表中,選取 [NuGet 封裝管理員]>[封裝管理員主控台]。 在 [套件管理員主控台] (PMC) 中,輸入下列命令:
Install-Package Microsoft.AspNet.WebApi.Client
上述命令會將下列 NuGet 套件新增至專案:
- Microsoft.AspNet.WebApi.Client
- Newtonsoft.Json
Newtonsoft.Json (也稱為 Json.NET) 是適用于 .NET 的熱門高效能 JSON 架構。
新增模型類別
檢查 Product
類別:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
這個類別符合 Web API 所使用的資料模型。 應用程式可以使用 HttpClient 從 HTTP 回應讀取 Product
實例。 應用程式不需要撰寫任何還原序列化程式碼。
建立和初始化 HttpClient
檢查靜態 HttpClient 屬性:
static HttpClient client = new HttpClient();
HttpClient 旨在具現化一次,並在整個應用程式的生命週期中重複使用。 下列條件可能會導致 SocketException 錯誤:
- 為每個要求建立新的 HttpClient 實例。
- 負載過重的伺服器。
為每個要求建立新的 HttpClient 實例可能會耗盡可用的通訊端。
下列程式碼會初始化 HttpClient 實例:
static async Task RunAsync()
{
// Update port # in the following line.
client.BaseAddress = new Uri("http://localhost:64195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
上述程式碼:
- 設定 HTTP 要求的基底 URI。 將埠號碼變更為伺服器應用程式中使用的埠。 除非使用伺服器應用程式的埠,否則應用程式將無法運作。
- 將 Accept 標頭設定為 「application/json」。 設定此標頭會告知伺服器以 JSON 格式傳送資料。
傳送 GET 要求以擷取資源
下列程式碼會傳送產品的 GET 要求:
static async Task<Product> GetProductAsync(string path)
{
Product product = null;
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product;
}
GetAsync方法會傳送 HTTP GET 要求。 當方法完成時,它會傳回包含 HTTP 回應的 HttpResponseMessage 。 如果回應中的狀態碼是成功碼,回應本文會包含產品的 JSON 標記法。 呼叫 ReadAsAsync ,將 JSON 承載還原序列化為 Product
實例。 ReadAsAsync方法是非同步,因為回應本文可以任意大。
當 HTTP 回應包含錯誤碼時,HttpClient不會擲回例外狀況。 相反地,如果狀態為錯誤碼, IsSuccessStatusCode 屬性為 false 。 如果您想要將 HTTP 錯誤碼視為例外狀況,請在回應物件上呼叫 HttpResponseMessage.EnsureSuccessStatusCode 。 EnsureSuccessStatusCode
如果狀態碼落在範圍 200–299 之外,就會擲回例外狀況。 請注意, HttpClient 可能會基於其他原因擲回例外狀況,例如,如果要求逾時。
Media-Type格式子還原序列化
在沒有參數的情況下呼叫 ReadAsAsync 時,它會使用一組預設的 媒體格式器 來讀取回應本文。 預設格式器支援 JSON、XML 和 Form-url 編碼的資料。
您可以使用 ReadAsAsync 方法的格式子清單,而不是使用預設格式器。 如果您有自訂媒體類型格式器,使用格式器清單會很有用:
var formatters = new List<MediaTypeFormatter>() {
new MyCustomFormatter(),
new JsonMediaTypeFormatter(),
new XmlMediaTypeFormatter()
};
resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);
如需詳細資訊,請參閱ASP.NET Web API 2 中的媒體格式器
傳送 POST 要求以建立資源
下列程式碼會傳送 POST 要求,其中包含 Product
JSON 格式的實例:
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync(
"api/products", product);
response.EnsureSuccessStatusCode();
// return URI of the created resource.
return response.Headers.Location;
}
PostAsJsonAsync方法:
- 將物件序列化為 JSON。
- 在 POST 要求中傳送 JSON 承載。
如果要求成功:
- 它應該會傳回 201 (Created) 回應。
- 回應應該會在 [位置] 標頭中包含所建立資源的 URL。
傳送 PUT 要求以更新資源
下列程式碼會傳送 PUT 要求來更新產品:
static async Task<Product> UpdateProductAsync(Product product)
{
HttpResponseMessage response = await client.PutAsJsonAsync(
$"api/products/{product.Id}", product);
response.EnsureSuccessStatusCode();
// Deserialize the updated product from the response body.
product = await response.Content.ReadAsAsync<Product>();
return product;
}
PutAsJsonAsync方法的運作方式類似PostAsJsonAsync,不同之處在于它會傳送 PUT 要求,而不是 POST。
傳送 DELETE 要求以刪除資源
下列程式碼會傳送 DELETE 要求來刪除產品:
static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
HttpResponseMessage response = await client.DeleteAsync(
$"api/products/{id}");
return response.StatusCode;
}
如同 GET,DELETE 要求沒有要求本文。 您不需要使用 DELETE 來指定 JSON 或 XML 格式。
測試範例
若要測試用戶端應用程式:
下載 並執行伺服器應用程式。 確認伺服器應用程式正常運作。 例如,
http://localhost:64195/api/products
應該傳回產品清單。設定 HTTP 要求的基底 URI。 將埠號碼變更為伺服器應用程式中使用的埠。
static async Task RunAsync() { // Update port # in the following line. client.BaseAddress = new Uri("http://localhost:64195/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json"));
執行用戶端應用程式。 此時會產生下列輸出:
Created at http://localhost:64195/api/products/4 Name: Gizmo Price: 100.0 Category: Widgets Updating price... Name: Gizmo Price: 80.0 Category: Widgets Deleted (HTTP Status = 204)
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應