WebSurfer's Home

Filter by APML

MVC5 で IHttpClientFactory を DI で利用

by WebSurfer 27. January 2025 14:26

下の図の構成で、ASP.NET MVC5 において Dependency Injection (DI) により IHttpClientFactory を取得し、それから HttpClient を生成して Web API からデータを取得し、そのデータをブラウザに表示する方法を書きます。

MVC5 で IHttpClientFactory を利用

ASP.NET Core MVC の例は先の記事「ASP.NET と HttpClient (CORE)」に書きました。

ASP.NET Core の場合は、Visual Studio のテンプレートを使ってプロジェクトを作成すればデフォルトで DI 機能が実装されるので、Program.cs で AddHttpClient メソッドを使って IHttpClientFactory を IServiceCollection (DI コンテナ) に登録するだけで、Controller はコンストラクタの引数経由で IHttpClientFactory を取得できます。

一方、ターゲットフレームワークが .NET Framework 場合、Visual Studio のテンプレートで作成した MVC5 アプリには DI 機能は実装されません。なので、最初の課題はそれにどのように DI 機能を追加するかになります。

ちなみに DI を利用して IHttpClientFactory を取得するのは必須です。何故かと言うと、Microsoft のドキュメント「IHttpClientFactory の代替手段」に書いてありますように、以下のことを回避できるというメリットがあるからです。

  • HttpMessageHandler インスタンスをプールすることによるリソース枯渇の問題
  • 一定の間隔で HttpMessageHandler インスタンスを循環させることによって発生する古くなった DNS の問題

ターゲットフレームワークが .NET Framework のアプリでも、バージョンが 4.6.2 以降であれば ASP.NET Core で DI に使われている Microsoft.Extensions.DependencyInjection 名前空間にあるクラス類を利用して DI 機能を実装できます。

.NET Framework 4.8 の MVC5 アプリに DI 機能を実装する詳しい方法は、先の記事「MVC5 での Dependency Injection」に書きました。この記事では、その記事のアプリの IServiceCollection (DI コンテナ) に IHttpClientFactory を登録し、それを Controller でどのように使って Web API に要求を出し、データを取得するかを書きます。

(1) Microsoft.Extensions.Http

NuGet パッケージ Microsoft.Extensions.Http をインストールします。これは AddHttpClient メソッドを使用して IHttpClientFactory を IServiceCollection(DI コンテナ)に登録できるようにするため必要です。

Microsoft.Extensions.Http

(2) AddHttpClient メソッドの追加

先の記事「MVC5 での Dependency Injection」に書いた Global.asax.cs のコード内の ConfigureServices メソッドに、以下のように AddHttpClient メソッドを追加します。この一行で Controller はコンストラクタの引数経由で IHttpClientFactory を受け取れるようになります。

// DI コンテナにサービスを登録するメソッド
private void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<ScopedThing>();
    services.AddTransient<HomeController>();

    // IHttpClientFactory を DI して利用できるよう追加
    services.AddHttpClient();
}

(3) Controller

Controller の例です。ブラウザが Hero アクションメソッドを呼び出すと、DI 機能により IHttpClientFactory が Controller のコンストラクタの引数経由で渡されます。

IHttpClientFactory から生成した HttpClient を使って Web API に要求を出して JSON 形式のデータを取得し、それを .NET の List<Hero> 型のオブジェクトにデシリアライズして View に渡しています。

using Mvc5DependencyInjection.Models;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Text.Json;

namespace Mvc5DependencyInjection.Controllers
{
    public class HomeController : Controller
    {
        private readonly ScopedThing _scopedThing;

        // IHttpClientFactory を DI して利用できるよう追加
        private readonly IHttpClientFactory _clientFactory;

        // コンストラクタの引数経由 IHttpClientFactory が DI される
        public HomeController(ScopedThing scopedThing, 
                              IHttpClientFactory clientFactory)
        {
            this._scopedThing = scopedThing;
            this._clientFactory = clientFactory;
        }

        // ・・・中略・・・

        public async Task<ActionResult> Hero()
        {
            // IHttpClientFactory から HttpClient を取得
            HttpClient client = _clientFactory.CreateClient();

            var url = "Web API の url";
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            HttpResponseMessage response = await client.SendAsync(request);
            List<Hero> list = null;

            if (response.IsSuccessStatusCode)
            {
                using (Stream responseStream =
                              await response.Content.ReadAsStreamAsync())
                {
                    list = await JsonSerializer.
                           DeserializeAsync<List<Hero>>(responseStream);
                }
            }

            return View(list);
        }
    }
}

(4) Model

namespace Mvc5DependencyInjection.Models
{
    public class Hero
    {
        public int id { get; set; }
        public string name { get; set; }
    }
}

(5) View

@model IEnumerable<Mvc5DependencyInjection.Models.Hero>

@{
    ViewBag.Title = "Hero";
}

<h2>Hero</h2>

<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.id)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.name)
        </th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.id)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.name)
            </td>
        </tr>
    }

</table>

(6) 実行結果

上のコードを実行するとブラウザには以下のように表示されます。

実行結果

Tags: , , ,

MVC

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。ブログ2はそれ以外の日々の出来事などのトピックスになっています。

Calendar

<<  March 2025  >>
MoTuWeThFrSaSu
242526272812
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar