LoginSignup
20
26

More than 3 years have passed since last update.

【C#】HttpClientでWeb APIクライアントを作る (チュートリアル)

Last updated at Posted at 2021-05-22

はじめに

HttpClientの使ってHTTP GET/PUT/POST/DELETEのWeb APIをコールする初歩的なアプリを作成した。
作成手順を紹介する。
チュートリアル的な内容

記事投稿の背景

HttpClientを使うのが、初めてだった。チュートリアルやサンプルコードを検索したが、私の期待に沿うものがなかった(検索結果は下記表の通り)。

No 検索結果 詳細
1 公式ドキュメント(リンク)にサンプルコードがない。 HTTPの基本的なメソッド(GET/PUT/POST/DELETE)を呼ぶメソッドのサンプルがない。
2 サーバアプリのサンプルが過剰だった クライアントと通信するサーバが必要になる。非公式のチュートリアル(リンク)を調べると、サーバアプリはDBアクセスを伴うコード例が多い。クライントからWeb APIをコールする方法を学ぶことが目的なので、DBアクセスなどは不要。準備するのもコストなので、サーバ側は極力シンプルにしたい。
3 非公式のチュートリアル(リンク)がGET/PUTのみで、情報不足。 サーバを準備しなくても、動作確認できるチュートリアルもあったが、サンプルがGET/PUTのみ。C#9.0の記法が混ざっている点も厄介。

想定読者

  • HttpClientを初めて使う人

開発環境

Visual Studio 2019(ASP.NETの開発設定済みのもの)
 未設定の場合はこちらを参照して下さい
フレーワーク:.NET Core2.1

作成手順

(1)ASP.NET Coreで単純なサーバアプリを作る。
 自動生成コードを利用するため、特別な知識は不要。
(2)Web APIクライアントアプリを作成する。
(3)Visual Studioを複数立ち上げて、サーバとクライアントをデバック実行して動作確認する。

(1)ASP.NET Coreで単純なサーバアプリを作る

ASP.NET Coreでプロジェクトを作成する。

ソリューションの名前は「SimpleWebServer」にした。
※名前は任意
image.png

学習目的で自分PCで動作確認するだけなので、HTTPS用の構成のチェックを外した
プロジェクトを生成する。
image.png

自動生成コードを確認する。

生成されたプロジェクトのControllersフォルダ直下にValuesController.csが存在することを確認する。
実装内容は下記の通り。

ValuesController.cs
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace SimpleWebServer.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<string> Get( int id )
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post( [FromBody] string value )
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put( int id, [FromBody] string value )
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete( int id )
        {
        }
    }
}

自動生成コードのWebAPI一覧

HTTPメソッド URL 対応関数と補足説明
GET http://localhost:19691/api/values public ActionResult> Get()
GET http://localhost:19691/api/values//{id} public ActionResult Get( int id )
idの有無で引、呼び出される関数か識別される。
POST http://localhost:19691/api/values public void Post( [FromBody] string value )
本記事では、HTTPのbodyの書式(Content-Typeヘッダ)は「application/json(JSON形式)」で渡す。
valueにJSON文字列が格納される。
PUT http://localhost:19691/api/values/{id} public void Put( int id, [FromBody] string value )
本記事では、HTTPのbodyの書式(Content-Typeヘッダ)は「application/json(JSON形式)」で渡す。
valueにJSON文字列が格納される。
DELETE http://localhost:19691/api/values/{id} public void Delete( int id )

ビルドできることを確認する。

デバック時の設定を確認する。

生成したプロジェクトを選択する。
Visual Studio の「プロジェクトのタブ」→「xxxxxのプロパティ(※)」を押下。

プロジェクトプロパティ.png

デバックのタブを押下する。
[ブラウザ起動]のチェックを外す。

ブラウザ起動解除.png

スクロールして、URLを確認する。クライアントでURLを入れるときに使用する。
アプリのURL.png

(2)単純なWebAPIクライアントアプリを作る

コンソールアプリケーションプロジェクトを作成する。

今回は.NET Core2.1を使用した。
image.png

この例では、JSONシリアライザにJSON.NETを利用する。Nugetパッケージからインストールすること。
image.png

クライアントの実装

URLはご自身のサーバの設定に合わせて、書き換えて下さい。

Program.cs
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace SimpleWebApiClient
{
    class Program
    {

        static async Task Main( string[] args )
        {
            var valueApi = new WebApiClient();
            await valueApi.GetAsync();
            await valueApi.PutAsync();
            await valueApi.PostAsync();
            await valueApi.DeleteAsync();
        }
    }

    /// <summary>
    /// Web APIクライアント
    /// </summary>
    public class WebApiClient
    {
        /// <summary>
        /// HTTPクライアント
        /// </summary>
        /// <remarks>
        /// IDisposableを継承しているが、usingで囲わないこと
        /// 要求ごとにインスタンス化すると、ソケットが枯渇する懸念があるため、避けたほうが良い。
        /// 参考
        ///  下記の[HttpClientを作成して初期化する]を参照
        ///  https://docs.microsoft.com/ja-jp/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
        ///  InfoQでも言及されている
        ///  https://www.infoq.com/jp/news/2016/09/HttpClient/
        /// </remarks>
        private static HttpClient Client = new HttpClient();

        /// <summary>
        /// GETメソッドをコールする
        /// </summary>
        /// <returns></returns>
        public async Task GetAsync()
        {
            try
            {
                //HTTP GET要求を送信する
                Console.WriteLine("Call GET api/values");
                var resource = await Client.GetAsync("http://localhost:19691/api/values");
                //ステータス異常の時に例外をスルーする
                resource.EnsureSuccessStatusCode();
                //HTTP応答を取得して表示する
                var responseBody = await resource.Content.ReadAsStringAsync();
                Console.WriteLine(responseBody);
            }
            catch(Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            Console.WriteLine("End");
        }

        /// <summary>
        /// PUTメソッドをコールする
        /// </summary>
        /// <returns></returns>
        public async Task PutAsync()
        {
            try
            {
                //HTTP PUT要求を送信する
                Console.WriteLine("Call PUT api/values/5");
                var testInput = "TestMessage";
                var jsonString = JsonConvert.SerializeObject(testInput);
                var data = new StringContent(jsonString, Encoding.UTF8, mediaType: "application/json");
                var response = await Client.PutAsync("http://localhost:19691/api/values/5", data);
                response.EnsureSuccessStatusCode();
            }
            catch(Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            Console.WriteLine("End");
        }

        /// <summary>
        /// POSTメソッドをコールする
        /// </summary>
        /// <returns></returns>
        public async Task PostAsync()
        {
            try
            {
                //HTTP POST要求を送信する
                Console.WriteLine("Call POST api/values");
                var testInput = "PostMessage";
                var jsonString = JsonConvert.SerializeObject(testInput);
                var data = new StringContent(jsonString, Encoding.UTF8, mediaType: "application/json");
                var response = await Client.PostAsync("http://localhost:19691/api/values", data);
                response.EnsureSuccessStatusCode();
            }
            catch(Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            Console.WriteLine("End");
        }
        /// <summary>
        /// DELETEメソッドをコールする
        /// </summary>
        /// <returns></returns>
        public async Task DeleteAsync()
        {
            try
            {
                //HTTP DELETE要求を送信する
                Console.WriteLine("Call DELETE api/values/5");
                var response = await Client.DeleteAsync("http://localhost:19691/api/values/5");
                response.EnsureSuccessStatusCode();
            }
            catch(Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            Console.WriteLine("End");
        }
    }
}

サーバとクライアントアプリをデバック実行する

Visual Studioのソリューションを2つ立ち上げた状態で下記手順を実施する(サーバ用、クライアント用の2つ)。

(3)動作確認

サーバをデバック実行する。

①サーバを先に立ち上げる。
②下記メソッドにブレークポイントを貼る。
③デバック実行する。

        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get(){//略}

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put( int id, [FromBody] string value ){}

        // POST api/values
        [HttpPost]
        public void Post( [FromBody] string value ){}
        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete( int id ){}

クライアントを実行する。

GETメソッドをコール

サーバ側のGETメソッドが呼ばれていたら、OKです。
サーバ側で返した下記文字列(※)はHTTP応答に付与されます。
※"value1", "value2"

クライアント側でHTTP応答を読み取ると、サーバで返した文字列が表示される。

GETメソッド.gif

PUTメソッドをコール

サーバが受け取った値がクライアントの送信内容に一致するか確認する。

Putメソッド.gif

POSTメソッドをコール

サーバが受け取った値がクライアントの送信内容に一致するか確認する。

POSTメソッド.gif

DELETEメソッドをコール

URIに指定した値(5)をサーバが受け取れば、OK。

DELETEメソッド.gif

まとめ

Web APIを呼び出すサンプル実装を示した(GET/PUT/POST/DELETE)。
今回は勉強のため、HttpClientに標準で定義されたメソッドのみを利用した。

記事では触れていないが、実装をより良くする手法として下記2つがある'次にクライアントを作るときは、組み込みたいと思う)。
(1)Microsoftが提供しているパッケージを使う。
例えば、Microsoft.Asp.Net.WebApi.Clientなど。
HttpClentの拡張メソッドが定義されているため、もっと楽に実装できそう。
参考

(2)IHttpClientFactoryを使う。こちらに解説記事があるため、ここでは触れない。

参考

No リンク 備考
1 HTTPClientクラス Microsoft公式ドキュメント。
2 Tutorial Teacher 非公式のチュートリアル(英語)。HttpClientの使用経験が全くない状態だと、情報過多だった。
3 ZetCode C# HttpClient 非公式のC# HttpClientのチュートリアル(英語)。
サーバが準備されており、サンプルソースを書いて動かせる点が良かった。
GET/PUTのみなのが、物足りない。C#9.0の記法が混ざっていることも厄介だった。
4 ASP.NET Coreを利用するためのVisual Studio 2019のインストール方法 QiitaにあったASP.NET Coreのインストール手順の記事。
5 .NET クライアントから Web API を呼び出す Microsoftの公式ドキュメント ASP.NET Web APIガイダンス。Microsoft.Asp.Net.WebApi.Clientパッケージを用いたWeb Apiクライアントの作成方法が記載されている。本記事の次のステップとして、この実装を真似ると良いと思う。
6 開発者を苦しめる.NETのHttpClientのバグと紛らわしいドキュメント InfoQの記事。HttpClientを使う上での注意点について述べられている。
7 HttpClientをusingで囲わないでください Qiitaの記事。タイトル通りの内容。
8 IHttpClientFactory を使って今はこれ一択と思った話 IHttpFactoryを紹介したQiitaの記事。
9 C# 今更ですが、HttpClientを使う HttpClientの使い方をまとめたQiitaの記事。
10 HttpClientのBaseAddressを使う方法 HttpClientのBaseAddressプロパティに関する記事
20
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
26