テスターですが何か?

ホビープログラマ略してHPです

Blobメタデータ登録時の SetMetadata メソッドの呼び出し

with one comment

こちらのエントリーを書いていて Blob データにメタデータ設定できると知って衝撃を受けた自分のツイートからはじましました。

image

以前 Blob を利用したアプリを作ったときは(いろいろあってすべて削除しましたが)画像を Blob Storage に保存していましたが、メタデータは別にTable Storage上に保存していたんですよね。ここここで必死にストレージへのアクセスを高速化していましたが、そもそも必要ないストレージへのアクセスを行なっていたんですね orz … CloudBlob クラスの Metadata プロパティを利用すると、 Blob データとメタデータをまとめて管理することができます。

この自分のつぶやきに対して、「メタデータの登録には SetMetadata() の呼び出しが必要ですよ」との情報を頂きましたが、MSDNのチュートリアルのコード(リンクの2.)を見ると SetMetadata() の呼び出しは行なっていません。すると、「今は SetMetadata() は必要ないの?」という流れになってきました。MSDN の CloudPageBlob.SetMetadata (CloudBlobクラスはCloudPageBlobクラスを継承しています) を見ると、SetMetadataを呼び出さないとメタデータ値は保存されないことが記載されています。

CloudPageBlob.SetMetadata メソッド

http://msdn.microsoft.com/ja-jp/library/ee772815.aspx

【解説】

SetMetadata メソッドは、BLOB の Metadata プロパティで指定されているメタデータ値を、サービスに書き込みます。 Metadata プロパティを設定しても、BLOB 参照のメタデータ値が設定されるだけです。メタデータ値をサービスに書き込むには、BeginSetMetadata または SetMetadata を呼び出す必要があります。

 

やべぇ、テンション上がってきた!!

MSDNのチュートリアルのコードにバグがあるのか、あまり知られていない事実を見つけたのかどちらかです。さっそくMSDNのチュートリアルのコードを実行してみます。

        private void SaveImage(string id, string name, string description, string tags,
                                string fileName, string contentType, byte[] data)
        {
            // blobコンテナを作成し、画像のbyte配列をアップロードする
            var blob = this.GetContainer().GetBlobReference(name);
            blob.Properties.ContentType = contentType;

            // 画像のメタデータを作成する
            var metadata = new NameValueCollection();
            metadata["id"] = id;
            metadata["Filename"] = fileName;
            metadata["ImageName"] = string.IsNullOrEmpty(name) ? "unknown" : name;
            metadata["Description"] = string.IsNullOrEmpty(description) ? "unknown" : description;
            metadata["Tags"] = string.IsNullOrEmpty(tags) ? "unknown" : tags;

            // blobへデータを追加し、コミットする
            blob.Metadata.Add(metadata);
            blob.UploadByteArray(data);
        }

image

登録できました (゚A゚;)ゴクリ Azure Storage Explorer で確認すると、きちんとデータが登録されていることが分かります。

image

では、コードにSetMetadata()の呼び出しを追加します。StorageClientExceptionが発生しました \(^o^)/

        private void SaveImage(string id, string name, string description, string tags,
                                string fileName, string contentType, byte[] data)
        {
            // blobコンテナを作成し、画像のbyte配列をアップロードする
            var blob = this.GetContainer().GetBlobReference(name);
            blob.Properties.ContentType = contentType;

            // 画像のメタデータを作成する
            var metadata = new NameValueCollection();
            metadata["id"] = id;
            metadata["Filename"] = fileName;
            metadata["ImageName"] = string.IsNullOrEmpty(name) ? "unknown" : name;
            metadata["Description"] = string.IsNullOrEmpty(description) ? "unknown" : description;
            metadata["Tags"] = string.IsNullOrEmpty(tags) ? "unknown" : tags;

            // -- SetMetadataの呼び出しを追加してみる
            blob.Metadata.Add(metadata);
            blob.SetMetadata();
            blob.UploadByteArray(data);
        }

image

( ゜д゜) ポカーン

「Blob のメタデータ登録にはSetMetadata()の呼び出しが必要だよ」

SetMetadata()の呼び出しなしでもちゃんと登録できた(MSDNのチュートリアルは間違ってない)

試しにSetMetadata()を追加してみたら、StorageClientException が発生 ← イマココ

え?何??事前に聞いてた話と全然違うんですけどwww MSDNの「CloudPageBlob.SetMetadata メソッド」のサンプルコードと、「Exploring Windows Azure Storage」のコードを見比べて見る… あ、

Blobデータを先に登録した場合は、メタデータの登録にSetMetadata()の呼び出しが必要かもしれない

論より証拠です、Blobデータを登録して SetMetadata() の呼び出しを行わないコードを書いてみます。

        private void SaveImage(string id, string name, string description, string tags,
                                string fileName, string contentType, byte[] data)
        {
            // blobコンテナを作成し、画像のbyte配列をアップロードする
            var blob = this.GetContainer().GetBlobReference(name);
            blob.Properties.ContentType = contentType;

            // 画像のメタデータを作成する
            var metadata = new NameValueCollection();
            metadata["id"] = id;
            metadata["Filename"] = fileName;
            metadata["ImageName"] = string.IsNullOrEmpty(name) ? "unknown" : name;
            metadata["Description"] = string.IsNullOrEmpty(description) ? "unknown" : description;
            metadata["Tags"] = string.IsNullOrEmpty(tags) ? "unknown" : tags;

            // -- 先にBlobデータを登録してSetMetadataを呼び出さない
            blob.UploadByteArray(data);
            blob.Metadata.Add(metadata);
        }

処理は正常終了しましたが、メタデータが登録されていません。

image

じゃ、SetMetadata() 呼び出しを追加してみましょう

        private void SaveImage(string id, string name, string description, string tags,
                                string fileName, string contentType, byte[] data)
        {
            // blobコンテナを作成し、画像のbyte配列をアップロードする
            var blob = this.GetContainer().GetBlobReference(name);
            blob.Properties.ContentType = contentType;

            // 画像のメタデータを作成する
            var metadata = new NameValueCollection();
            metadata["id"] = id;
            metadata["Filename"] = fileName;
            metadata["ImageName"] = string.IsNullOrEmpty(name) ? "unknown" : name;
            metadata["Description"] = string.IsNullOrEmpty(description) ? "unknown" : description;
            metadata["Tags"] = string.IsNullOrEmpty(tags) ? "unknown" : tags;

            // -- 先にBlobデータを登録してSetMetadataを呼び出す
            blob.UploadByteArray(data);
            blob.Metadata.Add(metadata);
            blob.SetMetadata();
        }

ちゃんとメタデータが登録されました!!

image

 

まとめ

  • Blobデータよりもメタデータを先に登録 → メタデータの登録にSetMetadataの呼び出しは不要、呼び出すとStorageClientExceptionが発生する
  • メタデータよりもBlobデータを先に登録 → メタデータの登録にSetMetadataの呼び出しが必要、呼び出さないとメタデータのみ登録されない

考察(根拠はありません)ですが、Blob Storageは Blob データ(テキスト、画像、動画など)保存時にコミットを行なっているため、Blob データ登録前にメタデータをプロパティにセットしておけば、別途SetMetadataの呼び出しが不要になるのではないかと思います。Blob データよりも先にメタデータを登録することを推奨しておけば、「なぜかメタデータだけ登録されない!!」という悲痛な叫びが減るのではないでしょうか。Azure SDK 1.6で検証してるので、過去バージョンではどのように動作するのか分かりませんが結構重要な(これだけで「Azure使えねぇ」と判断されてしまうのかも)情報だと思います。

今回作成したサンプルコードは以下からダウンロード可能です。「SetMetadata.zip」をダウンロードしてください。

https://skydrive.live.com/embed?cid=5549D6C74FFBB345&resid=5549D6C74FFBB345%212372&authkey=AK_2rBvDyXx5f_A

一言

「Blob データを登録する場合は、先にメタデータを登録しておくことを推奨。あとでメタデータを登録する場合はSetMetadata()を必ず呼び出すこと。」

自分のなかでTable Storage と Blob Storage のハマリどころが蓄積されてきたので、年内にまとめてブログにアップしようと思います。

Written by david9142

2011年12月11日 @ 12:58 AM

カテゴリー: WindowsAzure

Tagged with ,

コメント / トラックバック1件

Subscribe to comments with RSS.

  1. ありがとうございます!

    やま

    2012年6月22日 at 1:05 PM


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。