Azure Functions で設定情報を使いたい

Azure Functions で設定情報を `IConfiguration` 型で扱いたい。欲を言えば `IOptions<T>` で扱いたいというケースについて。

端的に言うとドキュメントに記載があります。以下のページにいくと Azure Functions での DI の仕方が書いてあって、その中には `IConfiguration` がプラットフォームから提供されているのでそれを使う感じです。

[.NET Azure Functions で依存関係の挿入を使用する](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-dotnet-dependency-injection)

## やってみよう

Azure Functions のプロジェクトを作成したら `Microsoft.Azure.Functions.Extensions` を参照に追加します。そして、Startup.cs クラスを作ります。Startup クラスは `Microsoft.Azure.Functions.Extensions.DependencyInjection.FunctionsStartup` クラスを継承して Configure メソッドで色々追加していきます。

以下のクラスはプラットフォームで提供しているから使ってもいいよってドキュメントに書いてあります

- Microsoft.Extensions.Configuration.IConfiguration
- Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider

デバッガーで止めてみると色々 (96 個!?) 登録されてるみたいですけど、あんまり登録されてるからって使わない方がいいのかもしれないですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/b179c103-2e76-c0da-728a-ca48f77000a7.png)

ここまで来たらこっちのもんです、適当に情報設定するためのクラスを定義します。例えば以下のように

```csharp
public class Info
{
    public string Name { get; set; }
}
```

そして `local.settings.json` に `Info:Name` というキーで適当な値を設定します。

```json:local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "Info:Name": "Hello world" 
  }
}
```

そして Startup.cs で `AddOptions` メソッドで登録します。

```csharp:Startup.cs
using FunctionApp2;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(Startup))]

namespace FunctionApp2
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddOptions<Info>()
                .Configure<IConfiguration>((info, configuration) => configuration.Bind("Info", info));
        }
    }
}
```

ここまでおぜん立てすると関数で利用できます。例えば、この Info の Name をそのまま返す関数を作るとこんな感じです。

```csharp:Function1.cs
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;
using Microsoft.Extensions.Options;

namespace FunctionApp2
{
    public class Function1
    {
        private readonly IOptions<Info> _info;

        public Function1(IOptions<Info> info)
        {
            _info = info;
        }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation(_info.Value.Name);
            return new OkObjectResult(_info.Value.Name);
        }
    }
}
```

実行してエンドポイントを叩くとこんな感じの結果になります。思った通りですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/8700a61f-beae-a33a-dcf7-c5b8d244d5d9.png)

Azure にデプロイした後は、Function App の構成に `Info__Name` のように local.settings.json では `:` 区切りで登録したものを以下のように `__` 区切りで登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/2116db51-6213-b1e2-50de-07ebe8a8c776.png)

エンドポイントを叩くと以下のようになりました。ちゃんと値が取れてますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/ccbcf589-f380-2c6b-655d-1973b334fbda.png)

いい感じ。