Azure SDK の NuGet パッケージが乱立してるせいで混乱
Azure を使ったアプリケーション開発をしようとしたとき、NuGetパッケージが乱立していて非常に困った。Microsoft.Azure で始まるものやAzureで始まるもの、Fluent がついてたりついてなかったり、さらには世の中にあるサンプルプログラムもこれらが混在していて、もうめちゃくちゃだよ。
たとえば Blob Storage を使おうとすると、Microsoft 公式の NuGet パッケージだけでもこんだけある。
- WindowsAzure.Storage
- Microsoft.Azure.Storage.Blob
- Azure.Storage.Blobs
- Microsoft.Azure.Management.Storage
- Microsoft.Azure.Management.Storage.Fluent
そこでこれらを整理して、どんな時にどのパッケージを使えばよいか分かるようにした。
パッケージの分類
Azure Storage のパッケージを例に分類。"~版"は勝手に命名。
パッケージには大きく分けて、サービスクライアント系とリソース管理系とがある。
サービスクライアント
Blob コンテナを作ったり Blob をアップロードしたりするためのパッケージ。
- WindowsAzure. で始まるパッケージは古いやつ
- Microsoft.Azure. で始まるパッケージが Stable 版
- Azure. で始まるパッケージは Preview 版
- 異なるバージョンのパッケージを同時に使うと開発者は死ぬ
リソース管理
Storage Account を作ったり変更したりするためのパッケージ。
- 通常版とFluent版は全くの別物 ※パッケージ名に惑わされてはいけない
- 通常版とFluent版を混在して使うことはお勧めしない
ちなみに通常版とFluent版とは GitHub リポジトリも分かれている
- SDK版 ⇒ Azure SDK for .NET
- Fluent版 ⇒ Azure Management Libraries for .NET
で、結局どれ使えばいいの?
好きなの使えばいいのでは。安定かつ新しいのは↓
- サービスクライアント:Microsoft.Azure.*
- リソース管理:Microsoft.Azure.Management.*.Fluent
次に各パッケージを使ったサンプルプログラムを載せてるので参考に。
サービスクライアントのサンプル
Storage Account に blob コンテナを作って blob をアップロードするサンプルプログラム。
WindowsAzure.Storage
// Install-Package WindowsAzure.Storage
var connectionString = "storage-connection-string";
var account = CloudStorageAccount.Parse(connectionString);
var client = account.CreateCloudBlobClient();
var container = client.GetContainerReference("test-container");
await container.CreateIfNotExistsAsync();
var blob = container.GetBlockBlobReference("test-blob.txt");
await blob.UploadTextAsync("test blob content");
var content = await blob.DownloadTextAsync();
Console.WriteLine(content);
Microsoft.Azure.Storage.Blob
WindowsAzure.Storage と同じ
// Install-Package Microsoft.Azure.Storage.Blob
var connectionString = "storage-connection-string";
var account = CloudStorageAccount.Parse(connectionString);
var client = account.CreateCloudBlobClient();
var container = client.GetContainerReference("test-container-2");
await container.CreateIfNotExistsAsync();
var blob = container.GetBlockBlobReference("test-blob-2.txt");
await blob.UploadTextAsync("test blob content 2");
var content = await blob.DownloadTextAsync();
Console.WriteLine(content);
Azure.Storage.Blobs
Microsoft.Azure.Storage.Blob から様変わりし、REST APIに忠実な感じ。ちょっと不便感。
// Install-Package Azure.Storage.Blobs
var connectionString = "storage-connection-string";
var containerClient = new BlobContainerClient(connectionString, "test-container-3");
await containerClient.CreateIfNotExistsAsync();
var blobClient = containerClient.GetBlobClient("bloblo.txt");
var stream = new MemoryStream(Encoding.UTF8.GetBytes("blob content222"));
await blobClient.UploadAsync(stream, overwrite: true);
var downloadInfo = await blobClient.DownloadAsync();
var contentStream = downloadInfo.Value.Content;
var content = new StreamReader(contentStream).ReadToEnd();
Console.WriteLine(content);
リソース管理のサンプル
ServicePrincipal を使って Storage Account を一覧を表示するサンプルプログラム。
Microsoft.Azure.Management.Storage
認証がめんどくさい
// Install-Package Microsoft.Azure.Management.Storage
// Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
var tenantId= "00000000-0000-0000-0000-000000000000";
var subscriptionId = "00000000-0000-0000-0000-000000000000";
var clientId = "00000000-0000-0000-0000-000000000000";
var clientSecret = "azure-application-secret";
var context = new AuthenticationContext("https://login.windows.net/" + tenantId);
var clientCredential = new ClientCredential(clientId, clientSecret);
var tokenResponse = await context.AcquireTokenAsync("https://management.azure.com/", clientCredential);
var accessToken = new TokenCredentials(tokenResponse.AccessToken);
var client = new StorageManagementClient(accessToken);
client.SubscriptionId = subscriptionId;
var storageAccounts = await client.StorageAccounts.ListAsync();
foreach (var acc in storageAccounts)
{
Console.WriteLine(acc.Name);
}
Microsoft.Azure.Management.Fluent
まぁ使いやすいかも?
// Install-Package Microsoft.Azure.Management.Fluent
// 注意:Microsoft.Azure.Management.Storage.Fluent ではない
var tenantId= "00000000-0000-0000-0000-000000000000";
var subscriptionId = "00000000-0000-0000-0000-000000000000";
var clientId = "00000000-0000-0000-0000-000000000000";
var clientSecret = "azure-application-secret";
var cred = new AzureCredentialsFactory()
.FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud);
var az = Azure
.Authenticate(cred)
.WithSubscription(subscriptionId);
var storageAccounts = await az.StorageAccounts.ListAsync();
foreach (var acc in storageAccounts)
{
Console.WriteLine(acc.Name);
}
さいごに
こんなパッケージを乱立させて開発者を混乱させた Microsoft さんには大いに反省していただきたいです