如何从 Azure Blob 存储将文件下载到浏览器

How to download a file to browser from Azure Blob Storage

我已经成功列出可用文件,但我需要知道如何将该文件传递到浏览器供用户下载,而不必将其保存到服务器

这是我获取文件列表的方式

var azureConnectionString = CloudConfigurationManager.GetSetting("AzureBackupStorageConnectString");
var containerName = ConfigurationManager.AppSettings["FmAzureBackupStorageContainer"];
if (azureConnectionString == null || containerName == null)
    return null;

CloudStorageAccount backupStorageAccount = CloudStorageAccount.Parse(azureConnectionString);
var backupBlobClient = backupStorageAccount.CreateCloudBlobClient();
var container = backupBlobClient.GetContainerReference(containerName); 
var blobs = container.ListBlobs(useFlatBlobListing: true);
var downloads = blobs.Select(blob => blob.Uri.Segments.Last()).ToList();

一旦用户点击一个文件,服务器就会响应

var blob = container.GetBlobReferenceFromServer(option);

var memStream = new MemoryStream();
blob.DownloadToStream(memStream);

Response.ContentType = blob.Properties.ContentType;
Response.AddHeader("Content-Disposition", "Attachment;filename=" + option);
Response.AddHeader("Content-Length", blob.Properties.Length.ToString());
Response.BinaryWrite(memStream.ToArray());

非常感谢 Dhananjay Kumar 这个解决方案

虽然 blob 内容可以通过 Web 服务器流式传输,并通过浏览器传送给最终用户,但此解决方案会给 Web 服务器(cpu 和 NIC)带来负载。

另一种方法是为最终用户提供要下载的所需 blob 的 uri,他们可以在 html 内容中单击它。例如https://myaccount.blob.core.windows.net/mycontainer/myblob.ext.

这个问题是如果内容是私有的,因为除非使用 public blob,否则上面的 uri 将无法工作。为此,您可以创建共享访问签名(或服务器存储的策略),然后生成附加到 uri 的散列查询字符串。这个新的 uri 在给定的时间长度(例如 10 分钟)内有效。

下面是一个为 blob 创建 SAS 的小例子:

var sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5);
sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10);
sasConstraints.Permissions = SharedAccessBlobPermissions.Read;

var sasBlobToken = blob.GetSharedAccessSignature(sasConstraints);

return blob.Uri + sasBlobToken;

请注意,开始时间设置为过去几分钟。这是为了处理时钟漂移。这是 full tutorial 我 grabbed/modified 此代码示例来自

通过使用直接 blob 访问,您将完全绕过您的 VM/web 角色 instance/web 站点实例(减少服务器负载),并让您的最终用户直接从 blob 存储中提取 blob 内容。您仍然可以使用您的 Web 应用程序来处理许可、决定传送哪些内容等。但是...这让您可以直接-link 到 blob 资源,而不是通过您的 Web 服务器流式传输它们。

如果您使用 ASP.NET(核心),您可以将内容流式传输到浏览器,而无需在服务器上保存文件,使用 FileStreamResult 即 IActionResult 将是更优雅的解决方案。

var stream = await blob.OpenReadAsync();
return File(stream, blob.Properties.ContentType, option);

我做了一个示例,您可以在其中上传和下载 blob 文件。

using System;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Collections.Generic;

namespace GetBackup
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string Config_string = "";

            using (StreamReader SourceReader = File.OpenText(@"appsettings.json"))
            {
                Config_string = await SourceReader.ReadToEndAsync();
            }

            var config = (JObject)JsonConvert.DeserializeObject(Config_string);

            if(config["Application_type"].ToString()== "Backup")
            {
                string Dir_path = config["Backup_Path"].ToString();
                string[] allfiles = Directory.GetFiles(Dir_path, "*.*", SearchOption.AllDirectories);


                string storageConnectionString = config["AZURE_STORAGE_CONNECTION_STRING"].ToString();
                CloudStorageAccount storageAccount;
                if (CloudStorageAccount.TryParse(storageConnectionString, out storageAccount))
                {
                    CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
                    CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("rtddata");
                    //await cloudBlobContainer.CreateAsync();

                    string[] ExcludeFiles = config["Exception_File"].ToString().Split(',');

                    foreach (var file in allfiles)
                    {
                        FileInfo info = new FileInfo(file);
                        if (!ExcludeFiles.Contains(info.Name))
                        {
                            string folder = (Dir_path.Length < info.DirectoryName.Length) ? info.DirectoryName.Replace(Dir_path, "") : "";
                            folder = (folder.Length > 0) ? folder + "/" : "";
                            CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(folder + info.Name);
                            await cloudBlockBlob.UploadFromFileAsync(info.FullName);
                        }

                    }

                }
            }
            
            else if (config["Application_type"].ToString() == "Restore")
            {
                string storageConnectionString = config["AZURE_STORAGE_CONNECTION_STRING"].ToString();
                CloudStorageAccount storageAccount;
               
                if (CloudStorageAccount.TryParse(storageConnectionString, out storageAccount))
                {
                    CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
                    CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("rtddata");
                    string Dir_path = config["Restore_Path"].ToString();

                    IEnumerable<IListBlobItem> results = cloudBlobContainer.ListBlobs(null,true);  
                    foreach (IListBlobItem item in results)
                    {
                        string name = ((CloudBlockBlob)item).Name;
                        if (name.Contains('/'))
                        {
                            string[] subfolder = name.Split('/');
                            if (!Directory.Exists(Dir_path + subfolder[0]))
                            {
                                Directory.CreateDirectory(Dir_path + subfolder[0]);
                            }
                            
                        }  
                            CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(name);
                            string path = (Dir_path + name);
                            blockBlob.DownloadToFile(path, FileMode.Create);
                    }
                    

                }
                    
            }

            
            
        }
    }
}