しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET Core 向けに Azure Table Storage を利用する Configuration Provider を書いた

タイトルの通りですが、ASP.NET Core と一緒に追加された Configuration 周りは Provider を実装すると簡単に拡張できるようになっているので、実際に Azure Table Storage 向けの実装を書いて試してみました。

流れとしては以下の 2 つを継承したクラスを実装するだけなので簡単です。

  • IConfigurationSource
  • ConfigurationProvider

Configuration 周りは同期処理として実行されるので、Task ベースの非同期とか使ってる場合には、デッドロックしないように ConfigureAwait(false) を付けたりと工夫が必要です。

サンプルに近い実装ですが、とりあえず GitHub に一式を公開しておきました。

デフォルトでは Key Vault 向け Provider が入っているのでそれを使えば良いという感じはしますが、Key Vault では ":" での区切りではなく "--" になったり、接続文字列以外のセキュリティが求められないパラメータ的なものまで入れるのは無駄な感じもします。

何より Azure Table は安くて容量も大きいので、使いどころはあるのではないかなと思います。

Provider 周りの実装は GitHub を見てもらうとして、残りはちょっとだけ設定周りについて書いておくことにします。この Provider は Azure Storage の接続文字列が必要になるので、Program.cs にある IWebHostBuilder のメソッド内で接続文字列を config から取得するようにします。

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
               .ConfigureAppConfiguration((context, config) =>
               {
                   var builtConfig = config.Build();

                   config.AddAzureTableStorage(builtConfig.GetConnectionString("StorageConnection"), builtConfig["TableName"], builtConfig["PartitionKey"]);
               })
               .UseStartup<Startup>();
}

デフォルトのファイルや環境変数からの設定後の値が ConfigureAppConfiguration のタイミングで取れるので、それを利用して Azure Storage の Provider を追加しています。

appsettings.json には以下のように書いていますが、TableName と PartitionKey はセクションにしても良いかもしれません。これらの設定は App Service の場合は App Settings からオーバーライド出来るので便利です。

{
  "TableName": "Config",
  "PartitionKey": "Primary",
  "ConnectionStrings": {
    "StorageConnection": "STORAGE_CONNECTION_STRING"
  }
}

この辺りの考え方は Key Vault の時と同じです。というかドキュメントに書いてあります。

テーブル名やプライマリキーは設定から読んでも良いし、固定値にしても良いと思います。Table の構造としては RowKey を Configration 内で参照するためのキーとして扱うようになっています。

なので Table には以下のような形でデータを投入することになります。

f:id:shiba-yan:20181206103012p:plain

後は実際にConfiguration から値を読み込むのですが、今回は Configure を使ってオプション値として扱ってみました。以下のようなコードを書くとセクション内の値をバインドしてくれます。

services.Configure<CustomModel>(Configuration.GetSection("Custom"));

コンストラクタインジェクションを使って受け取ったクラスには、ちゃんと Table Storage に書き込んだ値が入っていることが確認出来ます。

f:id:shiba-yan:20181206102816p:plain

Table Storage はツールが充実しているので、Azure Portal からポチポチ設定するより楽かもしれませんね。

フレームワーク側にデフォルトの実装がある程度用意されているので、カスタマイズは思ったよりも簡単でした。是非はともかく SQL Server や Cosmos DB などをソースとする Provider も実装も出来るはずです。

デフォルトの実装は非常に参考になるので、カスタマイズの際には参考にするとよい感じです。

Azure の場合は Key Vault で大体解決すると思いますが、AWS Secrets Manager や HashiCorp Vault などに対応した Provider は価値がありそうです。*1

*1:既にありそうな気もしますが調べてないです