24

私たちのASP.NET MVC 3アプリケーションはAzure上で動作し、Blobをファイルストレージとして使用しています。私はアップロード部分を考え出しました。MVC3でAzure Blobファイルをダウンロード

ビューにはファイル名が表示されます。このファイル名をクリックすると、ファイルのダウンロード画面が表示されます。

誰も私にこれを行う方法を教えてもらえますか?

答えて

52

実際には2つのオプションがあります。最初は、ユーザーをblobに直接リダイレクトするだけです(blobがパブリックコンテナにある場合)。それは少しのようになります。

return Redirect(container.GetBlobReference(name).Uri.AbsoluteUri); 

ブロブがプライベートコンテナ内にある場合、あなたは共有アクセス署名を使用して、前の例のようにリダイレクトを行う、あるいは、あなたのコントローラのアクションにブロブを読むことができる可能性のいずれかをし、ダウンロードとしてクライアントにそれを押し下げ:

Response.AddHeader("Content-Disposition", "attachment; filename=" + name); // force download 
container.GetBlobReference(name).DownloadToStream(Response.OutputStream); 
return new EmptyResult(); 
+0

これはプライベートなブロブですので、私が投稿する2番目のメソッドを使用していました。どうもありがとうございました! – James

+0

私はユーザーからファイル名を隠したい(そして自分自身を入れたい)、これを行う方法を知っていますか? – James

+2

Content-Dispositionヘッダーに必要な情報を入力してください。 – smarx

9

は、ここでプライベートブロブアクセスの再開可能なバージョン(大きなファイルのために有用またはビデオまたはオーディオの再生に求めることが可能)です。

public class AzureBlobStream : ActionResult 
{ 
    private string filename, containerName; 

    public AzureBlobStream(string containerName, string filename) 
    { 
     this.containerName = containerName; 
     this.filename = filename; 
     this.contentType = contentType; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var response = context.HttpContext.Response; 
     var request = context.HttpContext.Request; 

     var connectionString = ConfigurationManager.ConnectionStrings["Storage"].ConnectionString; 
     var account = CloudStorageAccount.Parse(connectionString); 
     var client = account.CreateCloudBlobClient(); 
     var container = client.GetContainerReference(containerName); 
     var blob = container.GetBlockBlobReference(filename); 

     blob.FetchAttributes(); 
     var fileLength = blob.Properties.Length; 
     var fileExists = fileLength > 0; 
     var etag = blob.Properties.ETag; 

     var responseLength = fileLength; 
     var buffer = new byte[4096]; 
     var startIndex = 0; 

     //if the "If-Match" exists and is different to etag (or is equal to any "*" with no resource) then return 412 precondition failed 
     if (request.Headers["If-Match"] == "*" && !fileExists || 
      request.Headers["If-Match"] != null && request.Headers["If-Match"] != "*" && request.Headers["If-Match"] != etag) 
     { 
      response.StatusCode = (int)HttpStatusCode.PreconditionFailed; 
      return; 
     } 

     if (!fileExists) 
     { 
      response.StatusCode = (int)HttpStatusCode.NotFound; 
      return; 
     } 

     if (request.Headers["If-None-Match"] == etag) 
     { 
      response.StatusCode = (int)HttpStatusCode.NotModified; 
      return; 
     } 

     if (request.Headers["Range"] != null && (request.Headers["If-Range"] == null || request.Headers["IF-Range"] == etag)) 
     { 
      var match = Regex.Match(request.Headers["Range"], @"bytes=(\d*)-(\d*)"); 
      startIndex = Util.Parse<int>(match.Groups[1].Value); 
      responseLength = (Util.Parse<int?>(match.Groups[2].Value) + 1 ?? fileLength) - startIndex; 
      response.StatusCode = (int)HttpStatusCode.PartialContent; 
      response.Headers["Content-Range"] = "bytes " + startIndex + "-" + (startIndex + responseLength - 1) + "/" + fileLength; 
     } 

     response.Headers["Accept-Ranges"] = "bytes"; 
     response.Headers["Content-Length"] = responseLength.ToString(); 
     response.Cache.SetCacheability(HttpCacheability.Public); //required for etag output 
     response.Cache.SetETag(etag); //required for IE9 resumable downloads 
     response.ContentType = blob.Properties.ContentType; 

     blob.DownloadRangeToStream(response.OutputStream, startIndex, responseLength); 
    } 
} 

例:

Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); // force download 
return new AzureBlobStream(blobContainerName, filename); 
+0

結果の 'Cache-Control'ヘッダをBLOBと同じにするにはどうすればよいですか? – dlras2

+0

「Util.Parse」とは何ですか? –

8

私はアクションメソッドからの応答ストリームへの書き込みがHTTPヘッダを台無しことに気づきました。予想されるヘッダーの一部が欠けていて、他のヘッダーが正しく設定されていません。

したがって、応答ストリームに書き込む代わりに、BLOBコンテンツをストリームとして取得し、Controller.File()メソッドに渡します。

CloudBlockBlob blob = container.GetBlockBlobReference(blobName); 
Stream blobStream = blob.OpenRead(); 
return File(blobStream, blob.Properties.ContentType, "FileName.txt"); 
関連する問題