依存性を注入することと依存性を逆転することにしか人生の喜びを感じられぬ土方プログラマー共。元気だったか。俺だよ。

俺たちはいつだってBlobServiceClientFactoryを探してきた。そうだろ?今日、お前らをこの執務室に集めたのは他でもない。ついにそのBlobServiceClientFactoryが見つかったんだ。

地の文:岡島が伝えた希望の言葉は、それでも開発者たちのコーディングする手を止めることは出来なかった。一瞥を投げかけたものもいたが、岡島が顔を向けるのを察すると焦るように作業に戻る。虚しさだけが漂っている執務室。壁の巨大掛け軸に描かれている「三代目大谷鬼次のDI」の絵図すら冷ややかな視線を投げかけているように見えた。

地の文:「どうせいつもの”オレオレBlobServiceClientFactory”なんだろ…」という、諦めにも似た気持ちが彼らの世界を支配していたのだ。岡島はおもむろに脱糞すると

~以下略~

◆結論

Best practices for using Azure SDK with ASP.NET Core

◆やりかた(ASP.NET)

  • Microsoft.Extensions.AzureのNugetPackageをプロジェクトに追加する。
  • Startup.csってのが元からあると思うんだけども、そこで「IServiceCollection」を引数に動いているメソッドを探す。
  • メソッドの中にとりあえず「services.AddAzureClients(b => { });」って書いてみる。
  • 「AddAzureClients」って記述がコンパイルエラー吐くので、カーソル合わせて「Ctrl + .」して「using Microsoft.Extensions.Azure;」する。

▼Blob

Azure.Storage.Blobsをプロジェクトに追加するべきかも。しなくていいケースもあるから、取り敢えず下のを真似っこして書いてみよ。

Startup.cs全体を載せとく。「AddAzureClients」って書いてるとこ(32行目から)をみてみてね。

「builder.AddBlobServiceClient」ってしてBlobの接続文字列を食わせる。そしてWithNameメソッドで任意の名前を付ける。つけなくてもいい。

使う側は以下の感じ。全文載せる。

  • お前さんのBlobに「test」っていう名前のコンテナがあるものとする。

「HogeController」なるコントローラーのコンストラクタで、「IAzureClientFactory<BlobServiceClient>」を引っ張って、なまはげまちゅりという名前を授けられしBlobClientをCreateClientしている。それだけ。

叩き方は以下の感じ。…普通だな!

curl --location --request POST 'https://localhost:44358/api/hoge/post' --header 'Content-Type: application/json' --data-raw '{"hoge":"hogehoge-"}'

内容はよしなに書き換えなさいな。

Azure Functionsでの使い方は知っ得情報のあとで。

◆知っ得情報

▼対応しているサービス

対応するパッケージは必要になるが、キューも読めるしKeyVaultの内容も読めるしCredentialの設定もできる。Blobの書き方知っていれば勘で書けそうなもんだが、実際のコードは元記事参照のこと。

▼WithName

必ずしもつけなくてもいいよ。「BlobServiceClient」をコンストラクタで受け取ればWithNameしてないBlobServiceClientを直で受け取ること出来まする。

public HogeController(BlobServiceClient blobServiceClient)

でもでも、アクセスしたいStorageが複数になっちゃったら詰むね。

▼環境変数

接続文字列をコードにベタ打ちしちゃってて意味ないよね~!

…説明いる?要らんだろ。こんな記事を既に読みに来てしまっているわけだし。appsettings.jsonでもApp Configurationでも何でも使えばいいだろが。

▼リトライとかの設定

「builder.ConfigureDefaults()」に、デフォルトコンフィグを渡すことできます。「IConfiguration」を受け取ることができるというガバいインターフェースを持ってくれているから、環境変数からGetSectionしてそのままぶち込んでもよかろう。

以下の書き方して、AzureDefaultsってGetSectionするとかね。

{
  "AzureDefaults": {
    "Retry": {
      "maxTries": 3
    }
  }
}

型安全にやりたいなら、Action<Azure.Core.ClientOptions>クラスっぽいものを渡す。RetryとかDiagnosticsとかTransportの設定ができるね。リトライ以外よぐわがんに゛ゃいです。

リトライの設定どうなってんのか知りたいならAzure.Core.RetryOptionsをながめろ。

個別に書くんなら以下のようにすりゃいいらしい。

builder.AddBlobServiceClient(Configuration.GetSection("CustomStorage")) 
    .WithName("CustomStorage")
    .ConfigureOptions(options => {
        options.Retry.Mode = Azure.Core.RetryMode.Exponential;
        options.Retry.MaxRetries = 5;
        options.Retry.MaxDelay = TimeSpan.FromSeconds(120); });

appsettings.jsonに書くなら以下で個別設定。

{
    "KeyVault": {
        "VaultUri": "https://mykeyvault.vault.azure.net",
        "Retry": {
            "maxRetries": 10
        }
    }
}

◆やりかた(Functions)

以下を読んでStartUp.csを追加する。

.NET Azure Functions で依存関係の挿入を使用する

そしてbuilder.Servicesに対して良い感じにする。

おわり。がんばれ。

◆うまあじ

  • DIのうまあじはもはや語る意味などないだろう。っていうか1記事書けちゃう。
  • もうAzure Storageのためのデータアクセス層とかつくらなくてよくない?すごく嬉しくない?
  • 今後、Azure SearchとかTableStorageとかCosmosとかその辺のも追加されていく。きっと。おそらく。たぶん。

◆余談:System.IO.Pipelines

Streamどうしをつなぐパイプみたいなものが欲しいよね。

.NET の System.IO.Pipelines

あ、あるの?

ストリームの例でやりかた書いてあるけども、なんか試す気おきねぇし、もうちょい使いやすい感じにした構文が欲しいですぅ。Stream全部読み切って全部出し切りたいだけなんですぅ。yieldみたいにクラスとか自動生成してたもれ。

ストリーム処理に興味ある人は非同期ストリームもチェックしとけ。

◆結論

BlobServiceClientFactoryはあったんです。Queueも行けるしKeyVaultもいけるし。

以上。じゃあな。