C# - Azure FunctionsでDI(Dependency injection)を利用する

DI(Dependency injection)とはオブジェクト間の依存関係をなくすために、クラスの中で必要なインスタンスを生成するのではなく、外で作られたインスタンスをセットするように設計しようという考え方です。

参考:C# - DI(Dependency injection)依存性の注入とは

 

そしてこの設計パターンをサポートしてくれるライブラリがDIコンテナです。

C#では「Microsoft.Extensions.DependencyInjection」というDIコンテナが用意されています。

参考:C# - DI(Dependency injection)コンテナを使う

 

Microsoft.Extensions.DependencyInjectionは Azure Functions でも利用できます。

(DI は Azure Functions 2.xからサポートされるようになったようです)

 ー 開発環境 ー 

Visual Studio 2019
.NET Core 3.1

NuGetからパッケージをインストールする

NuGetから「Microsoft.Azure.Functions.Extensions」をインストールしましょう。

Visual Studioの NuGetパッケージマネージャーからインストールすることができます。

 

メニューから「プロジェクト(P)」→「NuGet パッケージの管理(N)...」を選択します。

Microsoft.Azure.Functions.Extensions」を検索して「インストール」ボタンをクリックしインストールします。

DIコンテナに登録するテスト的なクラスを準備

DIコンテナの使い方をテストするために以下のようなクラスとインターフェースを用意しました。

このクラスをDIコンテナへ登録し、関数アプリから利用するという感じです。

    public interface ITestService
    {
        public string GetMessage();
    }


    public class DITestService : ITestService
    {
        public string GetMessage()
        {
            return "DITestServiceです";
        }
    }

DIコンテナにクラスを登録する

DIコンテナにクラスを登録するには FunctionsStartupクラスを使います。

FunctionsStartupクラスはアプリケーション(Azure Function)が起動したときに動作します。

FunctionsStartupクラスを継承したクラスを作成し、DIコンテナに必要なクラスを登録していきましょう。 

 

以下の例では FunctionStartupクラスを継承した Startupクラスを作成しています。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup((typeof(AzureFunctionTest.Startup)))]
namespace AzureFunctionTest
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton<DITestService>();
        }
    }
}

まずは [assembly:]属性に作成したクラスを指定します。(4行目)

これでアプリケーションが起動したときに作成したStartupのインスタンスが作成されるようになります。

 

続いて Configureメソッドをオーバーライドします。(9~12行目)

このメソッドの中でDIコンテナにクラスを登録していきます。

AddTransientメソッド ・・・ DIコンテナから取得するたびに新しいインスタンスが作成される
AddScopedメソッド  ・・・ Function実行ごとに新しいインスタンスが作成される

               (1回にFunction実行内では同じインスタンスが使われる)
AddSingletonメソッド ・・・ アプリケーションが存在し続ける間は同じインスタンスが使われる

関数アプリでインスタンスを取得

Functionクラスではコンストラクタでインスタンスを受け取ります。

 

Visual Studioで Azure Functionsテンプレートを使用すると 関数アプリのクラスは static で生成されます。

まずは static を外して 動的なクラスに変更しましょう。

続いてコンストラクタを追加してインスタンスを受け取ります。

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace AzureFunctionTest
{
    public class TestFunction
    {
        private readonly ITestService MyService;


        public TestFunction(ITestService service)
        {
            MyService = service;
        }

        [FunctionName("TestFunction")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            var message = MyService.GetMessage();

            return new OkObjectResult(message);
        }
    }
}