しばやん雑記

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

古い WindowsAzure.Storage SDK から新しい Storage SDK (v11 / v12) へ移行する

太古の昔から使われてきた WIndowsAzure.Storage SDK は未だに使えますが、そろそろ新しい SDK (v11 / v12) に移行しておくかという気分になってきたので、実際のプロジェクトで移行を行いました。

まだ使っているのかと言われると反論は難しいのですが、Azure Storage SDK は非常に広い範囲で使われていて依存関係が複雑かつ、アップグレードで得られるものが少なかったのもあります。特に Azure Functions は最近になって v11 へのアップグレードが行われたので、それに合わせる形にします。

サンプルとして以下のような Blob / Queue / Table を使うよくあるコードを用意しました。これを v11 と v12 へアップグレードしていくことにします。

using System;
using System.Threading.Tasks;

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using Microsoft.WindowsAzure.Storage.Table;

namespace ConsoleApp22
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var storageAccount = CloudStorageAccount.Parse("UseDevelopmentStorage=true");

            await BlobSampleAsync(storageAccount);
            await QueueSampleAsync(storageAccount);
            await TableSampleAsync(storageAccount);
        }

        private static async Task BlobSampleAsync(CloudStorageAccount storageAccount)
        {
            var blobClient = storageAccount.CreateCloudBlobClient();

            var container = blobClient.GetContainerReference("sample");

            await container.CreateIfNotExistsAsync();

            var blob = container.GetBlockBlobReference("buchizo.txt");

            await blob.UploadTextAsync("buchizo");
        }

        private static async Task QueueSampleAsync(CloudStorageAccount storageAccount)
        {
            var queueClient = storageAccount.CreateCloudQueueClient();

            var queue = queueClient.GetQueueReference("sample");

            await queue.CreateIfNotExistsAsync();

            await queue.AddMessageAsync(new CloudQueueMessage("buchizo"));
        }

        private static async Task TableSampleAsync(CloudStorageAccount storageAccount)
        {
            var tableClient = storageAccount.CreateCloudTableClient();

            var table = tableClient.GetTableReference("sample");

            await table.CreateIfNotExistsAsync();

            var operation = TableOperation.Insert(new SampleEntity
            {
                PartitionKey = "sample",
                RowKey = DateTime.UtcNow.ToString("yyyyMMddHHmmss"),
                Content = "buchizo"
            });

            await table.ExecuteAsync(operation);
        }
    }
}

新しく書くアプリケーションでは v12 の SDK を使うことをお勧めしますが、v11 から v12 へのアップデートは Managed Identity を使う場合以外には、積極的に行いたい理由はあまり無いように感じます。

ただし Blob Change Feed と Azure Data Lake Storage Gen 2 を使う場合には実質的に v12 以外の選択肢が無いです。どれかを v12 にした場合は全てアップグレードしましょう。

v11 SDK

既にレガシーと呼ばれていますが Azure Storage SDK v11 は実質的には WindowsAzure.Storage の名前空間の変更とアセンブリを機能ごとに分離したものなので、Blob と Queue に関しては新しいパッケージに入れなおして名前空間を変更すれば大体問題ないです。

ただし Table に関しては Storage SDK として提供されなくなりました。なので Table をこれまで通り使うには Cosmos DB の Table API の一機能として提供されている SDK を使う必要があります。

ドキュメントが用意されているのと、クラス周りはほぼ同じなので使い方は大体わかるはずです。

非常に厄介なのが Blob / Queue の SDK と Cosmos の Table SDK で同じ名前のクラスが存在することです。具体的には CloudStorageAccount が確実にコンフリクトします。

今回は using を使って Cosmos 側の CloudStorageAccount にエイリアスを付けることで対応しました。

using CloudStorageAccount = Microsoft.Azure.Storage.CloudStorageAccount;
using CloudTableStorageAccount = Microsoft.Azure.Cosmos.Table.CloudStorageAccount;
static async Task Main(string[] args)
{
    var storageAccount = CloudStorageAccount.Parse("UseDevelopmentStorage=true");

    await BlobSampleAsync(storageAccount);
    await QueueSampleAsync(storageAccount);

    var tableStorageAccount = CloudTableStorageAccount.Parse("UseDevelopmentStorage=true");

    await TableSampleAsync(tableStorageAccount);
}

この修正でコンパイルが通り、これまで通り動作するようになります。

しかし Azure Storage を使うために Cosmos DB 向けの SDK を使うというのは、非常に違和感があります。さらに古い Cosmos DB SDK が使われているので、二重で嫌なライブラリとなっています。

Azure Functions における v11 SDK

Azure Functions では最近まで WindowsAzure.Storage が使われていましたが、WebJobs Extensions v4 などで v11 SDK への対応がようやく行われました。

Visual Studio で Azure Storage を利用する Azure Functions を作成すると、以下のようにいくつかのライブラリで WindowsAzure.Storage が参照されていることが確認できます。

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

WindowsAzure.Storage への参照を無くすためには、以下の 2 つのライブラリを更新する必要があります。

この両方を更新することで古い参照が無くなり、v11 SDK のみが使われるようになりました。綺麗に参照が消えていることが確認できますし、IntelliSense でも出てこなくなります。

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

バインディングで CloudTable などの Storage SDK のクラスを使っている場合には名前空間が変わっている関係上、以下のような警告が出てくるようになります。単純に using を追加すれば解消します。

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

Storage SDK を直接使っていない場合は、パッケージの更新だけで v11 への移行が完了しました。

v12 SDK

Azure Storage SDK v12 は新しい規約に従って実装されているライブラリで、Key Vault や Cosmos DB v4 などいくつかのサービスはリリースされています。

最近のドキュメントは v12 ベースになっているので、新しいアプリケーションでは v12 を使っていけばよいです。API は v11 から v12 でシンプルになっていますが、互換性は無いので慣れるまで少しかかります。

この辺りの違いは実際のコードで知った方が速いと思うので、サンプルコードを出します。

今回は Storage の接続文字列を使っていますが、Managed Identity が必要な場合は Azure.Identity によって全ての新しい SDK で同じ方法で扱えます。

class Program
{
    static async Task Main(string[] args)
    {
        var connectionString = "UseDevelopmentStorage=true";

        await BlobSampleAsync(connectionString);
        await QueueSampleAsync(connectionString);
        await TableSampleAsync(connectionString);
    }

    private static async Task BlobSampleAsync(string connectionString)
    {
        var blobServiceClient = new BlobServiceClient(connectionString);

        var containerClient = blobServiceClient.GetBlobContainerClient("sample");

        await containerClient.CreateIfNotExistsAsync();

        var blobClient = containerClient.GetBlobClient("buchizo.txt");

        await blobClient.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("buchizo")));
    }

    private static async Task QueueSampleAsync(string connectionString)
    {
        var queueServiceClient = new QueueServiceClient(connectionString);

        var queueClient = queueServiceClient.GetQueueClient("sample");

        await queueClient.CreateIfNotExistsAsync();

        await queueClient.SendMessageAsync("buchizo");
    }

    private static async Task TableSampleAsync(string connectionString)
    {
        // 同じなので省略
    }
}

基本的には **Client というメソッドやクラスを使って処理を行います。多少オーバーロードが減っているので、単純な移行とはいきませんが難しくはないです。

Table Storage に関しては v11 と同じく v12 でも SDK がリリースされていませんが、今後追加される予定なのでその時にまた試してみたいと思います。ちなみに 9 月にプレビュー版がリリースされそうです。

この辺りがリリースされると Durable Functions 周りも v12 へのアップグレードが行われそうです。暫くは完全に WindowsAzure.Storage を無くすことは出来ませんが、あともう少しで完了しそうです。