Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Downloading Azure Blob files in MVC3

Our ASP.NET MVC 3 application is running on Azure and using Blob as file storage. I have the upload part figured out.

The View is going to have the File Name, which, when clicked will prompt the file download screen to appear.

Can anyone tell me how to go about doing this?

like image 514
James Avatar asked Jul 19 '11 18:07

James


2 Answers

Two options really... the first is to just redirect the user to the blob directly (if the blobs are in a public container). That would look a bit like:

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

If the blob is in a private container, you could either use a Shared Access Signature and do redirection like the previous example, or you could read the blob in your controller action and push it down to the client as a download:

Response.AddHeader("Content-Disposition", "attachment; filename=" + name); // force download container.GetBlobReference(name).DownloadToStream(Response.OutputStream); return new EmptyResult(); 
like image 178
user94559 Avatar answered Sep 21 '22 23:09

user94559


Here's a resumable version (useful for large files or allowing seek in video or audio playback) of private blob access:

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);     } } 

Example:

Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); // force download return new AzureBlobStream(blobContainerName, filename); 
like image 23
Michael Avatar answered Sep 19 '22 23:09

Michael