.NET クライアントから Web API を呼び出す (C#)Call a Web API From a .NET Client (C#)

by Mike Wasson および Rick Andersonby Mike Wasson and Rick Anderson

このコンテンツは、以前のバージョンの .NET 用です。This content is for a previous version of .NET. 新しい開発では、 ASP.NET Coreを使用する必要があります。New development should use ASP.NET Core. ASP.NET Core Web API の使用方法の詳細については、以下を参照してください。For more information on using ASP.NET Core Web API, see:

完成したプロジェクトをダウンロードします。Download Completed Project. ダウンロードの方法はこちらをご覧ください。Download instructions.

このチュートリアルでは、.NET アプリケーションから web API を呼び出す方法について説明しますThis tutorial shows how to call a web API from a .NET application, using System.Net.Http.HttpClient.

このチュートリアルでは、次の web API を使用するクライアントアプリを作成します。In this tutorial, a client app is written that consumes the following web API:

アクションAction HTTP メソッドHTTP method 相対 URIRelative URI
ID で製品を取得するGet a product by ID GETGET /api/id/api/products/id
新しい製品の作成Create a new product POSTPOST /api/製品/api/products
製品を更新するUpdate a product PUTPUT /api/id/api/products/id
製品を削除するDelete a product DELETEDELETE /api/id/api/products/id

ASP.NET Web API でこの API を実装する方法については、「 CRUD 操作をサポートする WEB api の作成」を参照してください。To learn how to implement this API with ASP.NET Web API, see Creating a Web API that Supports CRUD Operations.

わかりやすくするために、このチュートリアルのクライアントアプリケーションは Windows コンソールアプリケーションです。For simplicity, the client application in this tutorial is a Windows console application. Httpclient は、Windows Phone および Windows ストアアプリでもサポートされています。HttpClient is also supported for Windows Phone and Windows Store apps. 詳細については、「ポータブルライブラリを使用して複数のプラットフォームの WEB API クライアントコードを作成する」を参照してください。For more information, see Writing Web API Client Code for Multiple Platforms Using Portable Libraries

注: ベース Url と相対 Uri をハードコーディングされた値として渡す場合は、API を利用するための規則に注意して HttpClient ください。NOTE: If you pass base URLs and relative URIs as hard-coded values, be mindful of the rules for utilizing the HttpClient API. プロパティは、 HttpClient.BaseAddress 末尾のスラッシュ () を含むアドレスに設定する必要があり / ます。The HttpClient.BaseAddress property should be set to an address with a trailing forward slash (/). たとえば、ハードコーディングされたリソース Uri をメソッドに渡す場合は、 HttpClient.GetAsync 先頭にスラッシュを入れないでください。For example, when passing hard-coded resource URIs to the HttpClient.GetAsync method, don't include a leading forward slash. ID でを取得するには Product :To get a Product by ID:

  1. 一連 client.BaseAddress = new Uri("https://localhost:5001/");Set client.BaseAddress = new Uri("https://localhost:5001/");
  2. を要求 Product します。Request a Product. たとえば、client.GetAsync<Product>("api/products/4"); となります。For example, client.GetAsync<Product>("api/products/4");.

コンソール アプリケーションを作成するCreate the Console Application

Visual Studio で、 HttpClientSample という名前の新しい Windows コンソールアプリを作成し、次のコードを貼り付けます。In Visual Studio, create a new Windows console app named HttpClientSample and paste in the following code:

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();
        }
    }
}

上記のコードは、完全なクライアントアプリです。The preceding code is the complete client app.

RunAsync が実行され、完了するまでブロックされます。RunAsync runs and blocks until it completes. ほとんどの Httpclient メソッドは、ネットワーク i/o を実行するため、非同期です。Most HttpClient methods are async, because they perform network I/O. すべての非同期タスクは、内部で実行され RunAsync ます。All of the async tasks are done inside RunAsync. 通常、アプリはメインスレッドをブロックしませんが、このアプリは相互作用を許可しません。Normally an app doesn't block the main thread, but this app doesn't allow any interaction.

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 クライアントライブラリをインストールするInstall the Web API Client Libraries

NuGet パッケージマネージャーを使用して、Web API クライアントライブラリパッケージをインストールします。Use NuGet Package Manager to install the Web API Client Libraries package.

[ツール] メニューで、[NuGet パッケージ マネージャー] > [パッケージ マネージャー コンソール] の順に選択します。From the Tools menu, select NuGet Package Manager > Package Manager Console. パッケージマネージャーコンソール (PMC) で、次のコマンドを入力します。In the Package Manager Console (PMC), type the following command:

Install-Package Microsoft.AspNet.WebApi.Client

上記のコマンドは、プロジェクトに次の NuGet パッケージを追加します。The preceding command adds the following NuGet packages to the project:

  • WebApi (Microsoft AspNet. クライアント)Microsoft.AspNet.WebApi.Client
  • Newtonsoft.JsonNewtonsoft.Json

Netwonsoft.Json (Json.NET とも呼ばれます) は、.NET 用の一般的な高パフォーマンスの JSON フレームワークです。Netwonsoft.Json (also known as Json.NET) is a popular high-performance JSON framework for .NET.

モデルクラスの追加Add a Model Class

次の Product クラスを調べます。Examine the Product class:

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 によって使用されるデータモデルと一致します。This class matches the data model used by the web API. アプリは Httpclient を使用して、 Product HTTP 応答からインスタンスを読み取ることができます。An app can use HttpClient to read a Product instance from an HTTP response. アプリでは、逆シリアル化コードを記述する必要はありません。The app doesn't have to write any deserialization code.

HttpClient を作成して初期化するCreate and Initialize HttpClient

静的 Httpclient プロパティを確認します。Examine the static HttpClient property:

static HttpClient client = new HttpClient();

Httpclient は、1回だけインスタンス化し、アプリケーションの有効期間全体に再利用することを目的としています。HttpClient is intended to be instantiated once and reused throughout the life of an application. 次の状況では、 Socketexception エラーが発生する可能性があります。The following conditions can result in SocketException errors:

  • 要求ごとに新しい Httpclient インスタンスを作成しています。Creating a new HttpClient instance per request.
  • サーバーの負荷が高くなっています。Server under heavy load.

要求ごとに新しい Httpclient インスタンスを作成すると、使用可能なソケットが枯渇する可能性があります。Creating a new HttpClient instance per request can exhaust the available sockets.

次のコードでは、 Httpclient インスタンスを初期化します。The following code initializes the HttpClient instance:

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"));

上記のコードでは次の操作が行われます。The preceding code:

  • HTTP 要求のベース URI を設定します。Sets the base URI for HTTP requests. ポート番号を、サーバーアプリで使用するポートに変更します。Change the port number to the port used in the server app. サーバーアプリのポートが使用されていない場合、アプリは機能しません。The app won't work unless port for the server app is used.
  • Accept ヘッダーを "application/json" に設定します。Sets the Accept header to "application/json". このヘッダーを設定すると、JSON 形式でデータを送信するようにサーバーに指示されます。Setting this header tells the server to send data in JSON format.

GET 要求を送信してリソースを取得するSend a GET request to retrieve a resource

次のコードは、製品の GET 要求を送信します。The following code sends a GET request for a product:

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 要求を送信します。The GetAsync method sends the HTTP GET request. メソッドが完了すると、HTTP 応答を含む HttpResponseMessage が返されます。When the method completes, it returns an HttpResponseMessage that contains the HTTP response. 応答の状態コードが成功コードである場合、応答本文には製品の JSON 表現が含まれます。If the status code in the response is a success code, the response body contains the JSON representation of a product. Readasasync を呼び出して、JSON ペイロードをインスタンスに逆シリアル化し Product ます。Call ReadAsAsync to deserialize the JSON payload to a Product instance. 応答本文は任意に大きくなる可能性があるため、 Readasasync メソッドは非同期です。The ReadAsAsync method is asynchronous because the response body can be arbitrarily large.

Httpclient は、HTTP 応答にエラーコードが含まれている場合に例外をスローしません。HttpClient does not throw an exception when the HTTP response contains an error code. 状態がエラーコードの場合 、"プロパティ の報告" プロパティは false になります。Instead, the IsSuccessStatusCode property is false if the status is an error code. HTTP エラーコードを例外として扱う場合は、応答オブジェクトで EnsureSuccessStatusCode を呼び出します。If you prefer to treat HTTP error codes as exceptions, call HttpResponseMessage.EnsureSuccessStatusCode on the response object. EnsureSuccessStatusCode ステータスコードが 200 299 の範囲外になると、例外がスローさ – れます。EnsureSuccessStatusCode throws an exception if the status code falls outside the range 200–299. Httpclient は、要求がタイムアウトした場合など、他の理由で例外をスローする場合があることに注意 — してください。Note that HttpClient can throw exceptions for other reasons — for example, if the request times out.

逆シリアル化するフォーマッタの Media-TypeMedia-Type Formatters to Deserialize

パラメーターを使用せずに Readasasync を呼び出すと、既定の メディアフォーマッタ セットを使用して応答本文が読み取られます。When ReadAsAsync is called with no parameters, it uses a default set of media formatters to read the response body. 既定のフォーマッタは、JSON、XML、およびフォーム url でエンコードされたデータをサポートします。The default formatters support JSON, XML, and Form-url-encoded data.

既定のフォーマッタを使用する代わりに、フォーマッタのリストを Readasasync メソッドに渡すことができます。Instead of using the default formatters, you can provide a list of formatters to the ReadAsAsync method. カスタムのメディアタイプフォーマッタがある場合は、フォーマッタの一覧を使用すると便利です。Using a list of formatters is useful if you have a custom media-type formatter:

var formatters = new List<MediaTypeFormatter>() {
    new MyCustomFormatter(),
    new JsonMediaTypeFormatter(),
    new XmlMediaTypeFormatter()
};
resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);

詳細については、「 ASP.NET Web API 2 のメディアフォーマッタ」を参照してください。For more information, see Media Formatters in ASP.NET Web API 2

POST 要求を送信してリソースを作成するSending a POST Request to Create a Resource

次のコードは、インスタンスを含む POST 要求を Product JSON 形式で送信します。The following code sends a POST request that contains a Product instance in JSON format:

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 メソッド:The PostAsJsonAsync method:

  • オブジェクトを JSON にシリアル化します。Serializes an object to JSON.
  • POST 要求で JSON ペイロードを送信します。Sends the JSON payload in a POST request.

要求が成功した場合は、次のようになります。If the request succeeds:

  • このメソッドは、201 (Created) 応答を返します。It should return a 201 (Created) response.
  • 応答には、作成されたリソースの URL を Location ヘッダーに含める必要があります。The response should include the URL of the created resources in the Location header.

PUT 要求を送信してリソースを更新するSending a PUT Request to Update a Resource

次のコードは、製品を更新する PUT 要求を送信します。The following code sends a PUT request to update a 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;
}

PutAsJsonAsync メソッドは Postasjsonasync と同様に機能しますが、POST ではなく PUT 要求を送信する点が異なります。The PutAsJsonAsync method works like PostAsJsonAsync, except that it sends a PUT request instead of POST.

削除要求を送信してリソースを削除するSending a DELETE Request to Delete a Resource

次のコードは、削除要求を送信して製品を削除します。The following code sends a DELETE request to delete a product:

static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
    HttpResponseMessage response = await client.DeleteAsync(
        $"api/products/{id}");
    return response.StatusCode;
}

GET と同様、DELETE 要求には要求本文がありません。Like GET, a DELETE request does not have a request body. DELETE を使用して JSON または XML 形式を指定する必要はありません。You don't need to specify JSON or XML format with DELETE.

サンプルをテストするTest the sample

クライアントアプリをテストするには:To test the client app:

  1. サーバーアプリをダウンロードして実行します。Download and run the server app. ダウンロードの方法はこちらをご覧ください。Download instructions. サーバーアプリが動作していることを確認します。Verify the server app is working. たとえば、は http://localhost:64195/api/products 製品の一覧を返す必要があります。For example, http://localhost:64195/api/products should return a list of products.

  2. HTTP 要求のベース URI を設定します。Set the base URI for HTTP requests. ポート番号を、サーバーアプリで使用するポートに変更します。Change the port number to the port used in the server app.

    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"));
    
  3. クライアント アプリを実行します。Run the client app. 次の出力が生成されます。The following output is produced:

    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)