Azure Storage SDK for .NET v12 を使っていろいろしてたのですがドキュメント見ても良くわからないところがあったので補足用個人メモ。
書き込み用Streamが無い
BlobにアップロードするためのUploadメソッドなどはストリームを渡せるので、ASP.NET Core MVCやFileなどから得られたストリームを使ってそのままBlobに書き込むといった使い方はサンプルもあるしすぐわかります。
似たような感じで逐次ストリームに出力してBlobに書きだしたいと思ったのですけどぱっと見書き込み用Streamを受け取るメソッドが無いのですよね。。
結局いろいろ見てたら最新のv12のSDKだと Azure.Storage.Blobs.Specialized 名前空間にいろいろあるというオチでした。
public async Task Upload(string connectionString, string containerName, string blobName)
{
var storageAccount = new BlobServiceClient(connectionString);
var container = storageAccount.GetBlobContainerClient(containerName);
// GetBlockBlobClient and SetHttpHeadersAsync methods is defined in Azure.Storage.Blobs.Specialized
var blockBlob = container.GetBlockBlobClient(blobName);
using var stream = await blockBlob.OpenWriteAsync(overwrite: true);
using var tw = new StreamWriter(stream);
do
{
Console.Write("input data: ");
var input = Console.ReadLine();
if (string.IsNullOrEmpty(input)) break;
// write something to stream...
await tw.WriteLineAsync(input);
} while (true);
tw.Flush();
tw.Close();
await blockBlob.SetHttpHeadersAsync(new BlobHttpHeaders { ContentType = "text/plain" });
}
こんな感じで GetBlockBlobClient を使うとOpenWrite / OpenWriteAsync でそのBlobに対するStreamを得られます。あとは良しなにすればよいという感じ。GetBlobClient で大体のケースは問題ない気もしますがちょっと凝った感じにすると全然足らないですね。まぁ分かったらいいのですけど。。
あと Stream 経由でZip化するサンプルが Azure Tips & Tricks にあったので Blob に書き込むやつもついでに。サイトではBlobの内容を取得してZipに纏めるだったので、Blob にZipファイルを作ってStreamで逐次アーカイブしていく(圧縮はしない)という感じです。もうちょっと綺麗にかける気もしますけどまぁいいや。。
public async Task ZipUpload(string connectionString, string containerName, string blobName)
{
var storageAccount = new BlobServiceClient(connectionString);
var container = storageAccount.GetBlobContainerClient(containerName);
// GetBlockBlobClient and SetHttpHeadersAsync methods is defined in Azure.Storage.Blobs.Specialized
var blockBlob = container.GetBlockBlobClient(blobName);
using var stream = await blockBlob.OpenWriteAsync(overwrite: true);
using var zipstream = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(stream);
zipstream.SetLevel(0); // 0 - store only to 9 - means best compression
do
{
Console.Write("input filename: ");
var filename = Console.ReadLine();
if (string.IsNullOrEmpty(filename)) break;
using var memory = new MemoryStream();
Console.Write("\t input data: ");
await memory.WriteAsync(Encoding.UTF8.GetBytes(Console.ReadLine()));
// archive file
zipstream.PutNextEntry(new ICSharpCode.SharpZipLib.Zip.ZipEntry(filename)
{
Size = memory.Length
});
memory.Position = 0;
memory.CopyTo(zipstream);
zipstream.Flush();
} while (true);
await zipstream.FlushAsync();
zipstream.Close();
await blockBlob.SetHttpHeadersAsync(new BlobHttpHeaders { ContentType = "application/zip" });
}
SAS を生成する
ドキュメント見ても StorageSharedKeyCredential 使いますとか書いときながらその部分のコード例が無かったので(日本語に至ってはコードがまるまる漏れてる)一応。
public void GenerateSas(string connectionString, string account, string accountKey, string containerName, string blobName)
{
var storageAccount = new BlobServiceClient(connectionString);
var container = storageAccount.GetBlobContainerClient(containerName);
var blockBlob = container.GetBlobClient(blobName);
// SAS for blob
var sasBuilder = new BlobSasBuilder(BlobContainerSasPermissions.Read,
DateTimeOffset.UtcNow.AddDays(1)
)
{
BlobContainerName = containerName,
BlobName = blobName
};
var sharedKeyCred = new StorageSharedKeyCredential(account, accountKey);
var sasToken = sasBuilder.ToSasQueryParameters(sharedKeyCred).ToString();
Console.WriteLine($"url: {blockBlob.Uri}");
Console.WriteLine($"sasToken: {sasToken}");
}
StorageSharedKeyCredential はアカウント名とアカウントキーしか受け取らないのですよね。ストレージアカウントのキー(キー1,2)を使う場合は上記のような感じで生成できます。ユーザー委任SASとかを取得する場合は BlobSasBuilder の ToSasQueryParameters に渡す引数がユーザー委任キーとストレージアカウント名になります(StorageSharedKeyCredentialの代わりにGetUserDelegationKeyAsyncで得られるキーを使う)。こっちはちゃんとドキュメントに書いてる。。
まぁそんな感じです。
参考:https://gist.github.com/buchizo/5e007bf8ce23cc8dfae18afebdfc2fc5