虽然这有点超出常规,但我建议您做同样的事情,因为在.NET环境下开发时,这是最好的可扩展解决方案。
使用Azure存储!或任何其他类似的在线云存储解决方案。
- 它确保您的Web应用程序与文件分离,因此您不必担心将应用程序移动到不同的Web环境中。
- Web存储通常比Azure存储更昂贵(1GB大约需要3000个操作(读/写/列出),总共约为$0.03)。
- 当您扩展应用程序且停机时间更为关键时,使用交换/暂存技术时也适用于第1点。
- Azure存储负责过期所谓的Shared Access Tokens (SAS)。
为了简化您的工作,我将在此处包含我的代码,以便您无需搜索其余部分
因此,在我的情况下,我保存所有文件作为数据库中的附件
(当然不是实际文件)。
当有人请求附件时,我会快速检查过期日期是否已过,如果是,则应生成新的URL。
private async Task CheckSasExpire(IEnumerable<AttachmentModel> attachments)
{
foreach (AttachmentModel attachment in attachments)
{
await CheckSasExpire(attachment);
}
}
private async Task CheckSasExpire(AttachmentModel attachment)
{
if (attachment != null && attachment.LinkExpireDate < DateTimeOffset.UtcNow && !string.IsNullOrWhiteSpace(attachment.AzureContainer))
{
Enum.TryParse(attachment.AzureContainer, out AzureStorage.ContainerEnum container);
string url = await _azureStorage.GetFileSasLocator(attachment.Filename, container);
attachment.FileUrl = url;
attachment.LinkExpireDate = DateTimeOffset.UtcNow.AddHours(1);
await _attachmentRepository.UpdateAsync(attachment.AttachmentId, attachment);
}
}
AzureStorage.ContainerEnum
是一个内部枚举,用于轻松跟踪存储某些文件的容器,但这些当然可以是字符串
而我的 AzureStorage
类:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
public async Task<string> GetFileSasLocator(string filename, ContainerEnum container, DateTimeOffset expire = default(DateTimeOffset))
{
var cont = await GetContainer(container);
CloudBlockBlob blockBlob = cont.GetBlockBlobReference(filename);
DateTimeOffset expireDate = DateTimeOffset.UtcNow.AddHours(1);
if (expire != default(DateTimeOffset) && expire > expireDate)
{
expireDate = expire.ToUniversalTime();
}
SharedAccessBlobPermissions permission = SharedAccessBlobPermissions.Read;
var sasConstraints = new SharedAccessBlobPolicy
{
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-30),
SharedAccessExpiryTime = expireDate,
Permissions = permission
};
var sasToken = blockBlob.GetSharedAccessSignature(sasConstraints);
return blockBlob.Uri + sasToken;
}
private async Task<CloudBlobContainer> GetContainer(ContainerEnum container)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(_config["StorageConnectionString"]);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
string containerName = container.ToString().ToLower();
CloudBlobContainer cloudContainer = blobClient.GetContainerReference(containerName);
await cloudContainer.CreateIfNotExistsAsync();
return cloudContainer;
}
因此,它将生成以下URL:http://127.0.0.1:10000/devstoreaccount1/invoices/NL3_2002%20-%202019-04-12.pdf?sv = 2018-03-28&sr = b&sig = gSiohA%2BGwHj09S45j2Deh%2B1UYP1RW1Fx5VGeseNZmek%3D&st = 2019-04-18T14%3A16%3A55Z&se = 2019-04-18T15%3A46%3A55Z&sp = r
当然,在检索附件时,您必须应用自己的身份验证逻辑,以确定用户是否被允许查看文件。但是,这一切都可以通过JWT令牌在控制器或存储库中完成。如果有人能够得到URL,我不会担心URL是公共URL,如果他们能够在一个小时内得到它...那么就缩短过期日期:D
app.UseJwtBearerQueryString()
语句。 - Karel Kral