如何从 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);
}
}
}
}
}
}
我已经成功列出可用文件,但我需要知道如何将该文件传递到浏览器供用户下载,而不必将其保存到服务器
这是我获取文件列表的方式
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);
}
}
}
}
}
}