Descargar archivos Blob de Azure en MVC3
Nuestro ASP.NET La aplicación MVC 3 se ejecuta en Azure y utiliza Blob como almacenamiento de archivos. Tengo la parte de carga calculada.
La vista va a tener el Nombre del archivo, que, cuando se haga clic, aparecerá la pantalla de descarga de archivos.
¿Alguien puede decirme cómo hacer esto?
3 answers
Dos opciones realmente... la primera es redirigir al usuario directamente al blob (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 del controlador y enviarlo al cliente como una descarga:
Response.AddHeader("Content-Disposition", "attachment; filename=" + name); // force download
container.GetBlobReference(name).DownloadToStream(Response.OutputStream);
return new EmptyResult();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-20 03:46:41
Aquí hay una versión resumible (útil para archivos grandes o para permitir la búsqueda en la reproducción de video o audio) del acceso privado a 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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-04 03:33:19
Me di cuenta de que escribir en el flujo de respuesta desde el método action estropea las cabeceras HTTP. Faltan algunas cabeceras esperadas y otras no están configuradas correctamente.
Así que en lugar de escribir en el flujo de respuesta, obtengo el contenido del blob como un flujo y lo paso al Controlador.Método File ().
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
Stream blobStream = blob.OpenRead();
return File(blobStream, blob.Properties.ContentType, "FileName.txt");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-23 23:26:14