3

ユーザーが大きな画像 (最大約 100 MB) を Windows Azure Blob Storage サービスにアップロードできるようにする必要があるアプリケーションを構築しています。Windows Azure のファイル アップロードの最適化に関するRob Gillen の優れた記事を読み、 Parallel.Forループ内でCloudBlockBlob.PutBlock()メソッドを使用して、ファイル チャンクの並列アップロードを行うための彼のアプローチを借りました(コードはこちらから入手できます)。

私が抱えている問題は、ファイルをアップロードしようとするたびに、ストレージ クライアントから " InvalidMd5 " 例外が発生することです。問題は開発用ストレージにあるのではないかと疑い、ライブの Azure ストレージ アカウントに対してもコードを実行しようとしましたが、同じエラーが発生しました。Fiddlerでトラフィックを見ると、「Content-MD5」ヘッダーが有効な MD5 ハッシュに設定されていることがわかります。エラーの説明には、「リクエストで指定された MD5 値が無効です。MD5 値は 128 ビットで Base64 エンコードされている必要があります。」とありますが、私の知る限り、Fiddler で送信されている値は有効です (例a91c588092cedbdb1b82c2d3786fd509 )。

ハッシュの計算に使用するコードは次のとおりです (Rob Gillen の厚意による)。

public static string GetMD5HashFromStream(byte[] data)
{
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] retVal = md5.ComputeHash(data);

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }
    return sb.ToString();
}

そして、これは PutBlock() への実際の呼び出しです:

blob.PutBlock(transferDetails[j].BlockId, new MemoryStream(buff), blockHash, options);

私も次のようにハッシュを渡そうとしました:

Convert.ToBase64String(Encoding.UTF8.GetBytes(blockHash))

しかし、結果は同じでした-「InvalidMd5」エラー:(

base64 エンコード (例: YTkxYzU4ODA5MmNlZGJkYjFiODJjMmQzNzg2ZmQ1MDk= )を使用して PutBlock() に渡される MD5 ハッシュとそれを使用しない場合 (例: a91c588092cedbdb1b82c2d3786fd509 ) は、違いを生むようには見えません。

ロブのコードは明らかに彼のために働いていました.私の場合、何が問題を引き起こしているのか本当にわかりません. Rob のコードに加えた唯一の変更は、ParallelUpload() 拡張メソッドを変更して、ファイル名の代わりに Stream を取得し、アップロードするファイルのサイズに応じてブロック サイズを動的に決定することです。

この問題を解決する方法を知っている人がいたら、教えてください! 本当に感謝します!私はすでにこれに苦労して2日を失いました。

4

2 に答える 2

3

ロブ、助けを申し出て、MD5ハッシュの違いを指摘してくれてありがとう。あなたの答えは私に正しい方向に考えさせました。私はこれを掘り下げるためにもう1日を費やしましたが、幸運にも(そしてあなたの発言のおかげで:))私はついに問題を解決することができました。私の場合、実際には2つの問題があったことがわかりました。

1)MD5ハッシュ:回答に貼り付けたハッシュが、取得したハッシュよりも短いことに気付きましたが、正確に2倍短いことを確認するのに時間がかかりました。いくつかの実験の結果、テストアプリケーションのGetMD5HashFromStream()メソッドが、 MD5CryptoServiceProviderによって生成された16バイトのハッシュを32文字の文字列に変換していることがわかりました。そして、 Base64に変換されてPutBlock()メソッドに渡されたために問題を引き起こしたのは、この32文字の文字列でした。したがって、blobストレージサービスが不満を言っていたのは、2倍長く無効なハッシュです。これが私が最終的に得たコードです:

オリジナル:

public static string GetMD5HashFromStream(byte[] data)
{
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] retVal = md5.ComputeHash(data);

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }
    return sb.ToString();
}

およびPutBlock()の呼び出し:

// calculate the block-level hash
string blockHash = Helpers.GetMD5HashFromStream(buff);
blob.PutBlock(transferDetails[j].BlockId, new MemoryStream(buff), blockHash, options);

最後の:

MD5 md5 = new MD5CryptoServiceProvider();
byte[] blockHash = md5.ComputeHash(buff);
string convertedHash = Convert.ToBase64String(blockHash, 0, 16);
blob.PutBlock(transferDetails[j].BlockId, new MemoryStream(buff), convertedHash, options);

ロブ、私はあなたのコードがあなたのケースでどのように機能し、なぜそれが私のものではなかったのか本当に興味があります-それは私のマシンのセットアップに固有のものですか、それともAzureツールの異なるバージョン(私はv1を使用しています)です。 2)...何かアイデアがあれば教えてください。

2)開発ストレージのバグ:Webを何度も調べた結果、開発ストレージのあいまいだが明らかに既知のバグについて言及しているこのページにたどり着きました。

2つのリクエストが開発ストレージにまだ存在しないblobにブロックをアップロードしようとすると、1つのリクエストがblobを作成し、もう1つのリクエストがステータスコード409(競合)を返し、ストレージサービスのエラーコードBlobAlreadyExistsが返される場合があります。

これを回避するために私が思いついたものは次のとおりです。

public static bool IsDevelopmentStorageRunning()
{
    return new Microsoft.ServiceHosting.Tools.DevelopmentStorage.DevStore().IsRunning();
}

マシンの「C:\ ProgramFiles \ Windows Azure SDK \ v1.2\bin 」にあるMicrosoft.ServiceHosting.Tools.dllへの参照を追加する必要があります。次に、次のようにファイルチャンクを処理するParallel.Forループの前にこのメソッドを使用します。

bool isDevStorageRunning = StorageProxy.IsDevelopmentStorageRunning();
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = isDevStorageRunning ? 1 : 4;
Parallel.For(0, transferDetails.Length, parallelOptions, j => { ... });

これが私が経験したすべての面倒を誰かに救うことを願っています。ロブ、助けてくれてありがとう:)

于 2010-11-04T18:51:47.420 に答える
3

tishon、

この投稿を見た後、戻ってコードを再テストしましたが、渡されるデータ(おそらく関数に渡されるもの)に問題があると思います。

すぐに私に飛び出したのは、あなたが提供したmd5ハッシュでした...私がテストしたすべてのケースで、私のmd5ハッシュは次のような2つの等号で終わります(フィドラーからキャプチャ):

コンテンツ-MD5:D1Mxthoqhlwm9cC0729mWA ==

私は暗号の専門家ではありませんが、ブロックBLOBのブロックIDを操作することで、base64でエンコードされた値に変換する前にBLOB IDに無効/安全でない文字が含まれていると、無効なデータとブロックIDが取得されることを知っています。そのAzureは解釈できません。

于 2010-11-03T21:33:08.980 に答える