.NET クライアントから Web API を呼び出す (C#)
このコンテンツは、以前のバージョンの .NET 用です。 新しい開発では、ASP.NET Core を使用する必要があります。 ASP.NET Core Web API の使用の詳細については、以下を参照してください。
このチュートリアルでは、System.Net.Http.HttpClient. を使って、.NET アプリケーションから Web API を呼び出す方法を示します。
このチュートリアルでは、次の Web API を使うクライアント アプリを作成します。
アクション | HTTP メソッド | 相対 URI |
---|---|---|
ID で製品を取得する | GET | /api/products/id |
新しい製品の作成 | 投稿 | /api/products |
製品を更新する | PUT | /api/products/id |
製品を削除する | DELETE | /api/products/id |
ASP.NET Web API を使ってこの API を実装する方法については、CRUD 操作をサポートする Web API の作成に関する記事を参照してください。
わかりやすくするために、このチュートリアルのクライアント アプリケーションは Windows コンソール アプリケーションです。 HttpClient は、Windows Phone および Windows ストア アプリでもサポートされています。 詳細については、「ポータブル ライブラリを使った複数のプラットフォームに対応する Web API クライアント コードの作成」を参照してください
注: ベース URL と相対 URI をハードコーディングされた値として渡す場合は、HttpClient
API の使用に関する規則に注意してください。 HttpClient.BaseAddress
プロパティは、末尾にスラッシュが付いているアドレス (/
) に設定する必要があります。 たとえば、ハードコーディングされたリソース URI を HttpClient.GetAsync
メソッドに渡すときは、先頭にスラッシュを含めないでください。 ID で 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 を呼び出します。 状態コードが 200 から 299 の範囲に含まれない場合、EnsureSuccessStatusCode
は例外をスローします。 HttpClient は、要求がタイム アウトした場合など、他の理由で例外をスローする可能性があることに注意してください。
逆シリアル化するメディア型フォーマッタ
パラメーターを指定せずに ReadAsAsync を呼び出すと、既定のセットの "メディア フォーマッタ" を使って応答本文を読み取ります。 既定のフォーマッタは、JSON、XML、フォーム 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 要求の送信
次のコードを使って、JSON 形式の Product
インスタンスを含む POST 要求を送信します。
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 が Location ヘッダーに含まれているはずです。
リソースを更新するための 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 メソッドは、POST ではなく PUT 要求を送信する点を除けば、PostAsJsonAsync と同様に機能します。
リソースを削除するための 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)