from example asp.net-mvc asp.net-mvc-3 azure azure-storage azure-storage-blobs

asp.net-mvc - from - azure blob storage example c#



Descarga de archivos Azure Blob en MVC3 (3)

Nuestra aplicación ASP.NET MVC 3 se ejecuta en Azure y usa Blob como almacenamiento de archivos. Tengo la parte de carga resuelta.

La Vista tendrá el Nombre de archivo, que, al hacer clic en él, solicitará que aparezca la pantalla de descarga de archivos.

¿Alguien puede decirme cómo hacer esto?


Aquí hay una versión reanudable (útil para archivos de gran tamaño o para permitir la búsqueda en video o reproducción de audio) de acceso privado blob:

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

Ejemplo:

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


Dos opciones realmente ... la primera es simplemente redirigir al usuario al blob directamente (si los blobs están en un contenedor público). Eso se vería un poco como:

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

Si el blob está en un contenedor privado, puede usar una Firma de acceso compartido y hacer una redirección como en el ejemplo anterior, o puede leer el blob en la acción de su controlador y presionarlo hacia abajo para descargarlo al cliente:

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


Noté que escribir en el flujo de respuesta del método de acción arruina los encabezados HTTP. Algunos encabezados esperados faltan y otros no están configurados correctamente.

Entonces, en lugar de escribir en la secuencia de respuesta, obtengo el contenido blob como una secuencia y lo paso al método Controller.File ().

CloudBlockBlob blob = container.GetBlockBlobReference(blobName); Stream blobStream = blob.OpenRead(); return File(blobStream, blob.Properties.ContentType, "FileName.txt");