Azure を使った開発では欠かせないのが Storage ですが、最新の Azure Storage Client 7.0.1-preivew からは .NET Core に対応しているので、ASP.NET Core アプリに簡単に組み込めます。
これまでと変わらずに NuGet を使ってインストールするだけで準備は完了します。プレビューなので -Pre スイッチを付けないとインストール出来ないので、少しだけ注意が必要です。
Install-Package WindowsAzure.Storage -Pre
インストールしてしまえばこれまでと同じように使えますが、ASP.NET Core では設定の必要なサービスを ConfigureService 内で DI コンテナに登録するのが一般的になりそうなので、他のサービスの真似をしつつ Azute Storage を使えるようにします。
接続文字列は Configuration.GetConnectionString で取れるので、最低限のコードは以下のようになります。
public void ConfigureServices(IServiceCollection services) { services.AddScoped(_ => CloudStorageAccount.Parse(Configuration.GetConnectionString("DefaultStorageConnection"))); }
これでコンストラクタに CloudStorageAccount を受け取るようにすると、設定に書いた接続文字列で初期化済みのストレージアカウントが自由に扱えるようになります。
public class StorageController { public StorageController(CloudStorageAccount storageAccount) { // BlobClient を作成する var blobClient = storageAccount.CreateCloudBlobClient(); } }
Startup クラスで接続文字列を設定するので、使う側は気にせずに利用できるようになります。
ASP.NET Core の Dependency Injection は IServiceProvider を実装しているので、GetService メソッドで任意の型のインスタンスを取得出来ます。さらに CloudBlobClient を DI で取得できるようにしてみます。
public void ConfigureServices(IServiceCollection services) { services.AddScoped(_ => CloudStorageAccount.Parse(Configuration.GetConnectionString("DefaultStorageConnection"))); // DI で CloudStorageAccount を取得して CloudBlobClient を作成して返す services.AddScoped(provider => provider.GetService<CloudStorageAccount>().CreateCloudBlobClient()); }
AddScoped メソッドでは IServiceProvider が渡されるので、簡単に他のインスタンスが取得できます。実際に実行して試してみたところ、ちゃんと CloudBlobClient のインスタンスが取れていることが分かります。
これで使う分には問題なさそうですが、ASP.NET Core では IServiceCollection への拡張メソッドを作成して、DI コンテナへの追加から設定までを行うのが作法っぽいので、実際にコードを用意してみました。
オプションとして開発ストレージを使うのかどうかの項目を追加してみました。
public static class ServiceCollectionExtensions { public static void AddAzureStorage(this IServiceCollection services, Action<AzureStorageOptions> setupAction) { services.AddSingleton(_ => AzureStorageOptionsFactory(setupAction)); services.AddScoped(provider => { var options = provider.GetRequiredService<AzureStorageOptions>(); return options.UseDevelopmentStorage ? CloudStorageAccount.DevelopmentStorageAccount : CloudStorageAccount.Parse(options.ConnectionString); }); services.AddScoped(provider => provider.GetRequiredService<CloudStorageAccount>().CreateCloudBlobClient()); } private static AzureStorageOptions AzureStorageOptionsFactory(Action<AzureStorageOptions> setupAction) { var options = new AzureStorageOptions(); setupAction(options); return options; } } public class AzureStorageOptions { public bool UseDevelopmentStorage { get; set; } public string ConnectionString { get; set; } } public static class AzureStorageOptionsExtensions { public static AzureStorageOptions UseDevelopmentStorage(this AzureStorageOptions options) { options.UseDevelopmentStorage = true; return options; } public static AzureStorageOptions UseStorageAccount(this AzureStorageOptions options, string connectionString) { options.ConnectionString = connectionString; return options; } }
少し長めのコードですが、やっていることは大して変わっていません。オプションを保持するクラスはシングルトンにして、最初の 1 回だけ初期化するようにして後は使いまわすようにしています。
用意した拡張メソッドを使って ConfigureServices を修正すると以下のようになります。
public void ConfigureServices(IServiceCollection services) { services.AddAzureStorage(options => options.UseStorageAccount(Configuration.GetConnectionString("DefaultStorageConnection"))); }
最初に出したコードより分かりやすくなりました。本当はちゃんと Builder を用意して、最終的な成果物として Option を返すようにしないといけないのですが、今回はサンプルということで省きました。
ASP.NET Core では設定が必要な処理は Startup に集めておくと幸せになれると思います。