Azure FunctionsでのDI(Dependency Injection)
2020-08-21
azblob://2022/11/11/eyecatch/2020-08-20-azure-functions-di-000-e1597908184676.png

こんにちは、最近Azure Functionsを触ることが多い石川です。Azure Functionsを使うにあたり、DIをするといろいろ楽なことが多いので今回はその方法について紹介します。

Startup...?

Function Appを作成するときにテンプレートから展開すると以下のようなファイル構成になります。

ASP.NET CoreでDIを利用するにはStartup.csでIServiceCollectionに対象の追加などの定義を行います。ASP.NET Coreを使用している場合、起動時にProgram.csが実行されそこからStartup.csが呼び出される形で初期設定を行いますが、Function Appでは明示的に起動時に実行されるものが存在しないため手で作る必要があります。

では早速書いていきましょう。

書く前に...

早速書いていきたいところですが依存パッケージを先にインストールする必要があります。

Install-Package Microsoft.Azure.Functions.Extensions

上記をNugetからインストールしないとDIできません。

実際に書いていく

準備も整ったところで書いていきましょう。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;

[assembly: FunctionsStartup((typeof(FIXER.techblog.Startup)))]
namespace FIXER.Techblog
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // ここでDIコンテナに登録していく
        }
    }
}

見慣れませんが、namespaceの上に

[assembly: FunctionsStartup((typeof(<起動時に実行したいクラス名>)))]

と書くのが特徴的です。ここのクラス名はStartupでもなくていいのですが慣習っぽいのでStartupとしています。あと特筆するならば FunctionsStartup クラスを継承していることですかね。

DIコンテナに登録

ここまでできるとあとはASP.NET Coreと同じ感覚で扱えます。ConfigureメソッドでDIしたいものを定義していくだけです。

public override void Configure(IFunctionsHostBuilder builder)
{
    // HttpClientを登録
    builder.Services.AddHttpClient();

    // HogeServiceを登録
    builder.Services.AddScoped<IHogeService, HogeService>();

    // DbContextを登録
    builder.Services.AddDbContext<HogeContext>(o => o.UseSqlServer(Environment.GetEnvironmentVariable("connectionString")))
}

もちろんですが、必要なものはusingしてあげてください。例えば、AddHttpClient メソッドを使いたい時には Microsoft.Extensions.DependencyInjection パッケージをusingしてあげる必要があります。

DIされたオブジェクトを使う

DIコンテナに登録はできたので、あとは関数にインジェクトして使うだけです。こちらもASP.NET Coreと同様にコンストラクタで処理します。

namespace FIXER.Techblog
{
    public class BlogHelper
    {
        private readonly IHttpClientFactory _clientFactory;

        // コンストラクタでインジェクション
        public BlogHelper(IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory;
        }

        [FunctionName("BlogHelper")]
        public async Task<IActionResult> Run ([HttpTrigger]....) // 省略
        {
            var client = _clientFactory.CreateClient();
            // 以下略
        } 
    }

ざっくりとですが以上のような感じでAzure FunctionsでもDIパターンを使ってアプリを書くことができます。

「従量課金プランで1日1回だけTimer Triggerで実行するもの」などの実行回数が少ない場合は意識しなくていいと思いますが、頻繁に実行されるものはコネクションを使いまわせるようにDIを使っておいた方が無難でしょう。

特にHttpClientの扱いには気をつけましょう。

それでは。

参考