虽然这有点开箱即用,但我建议您也这样做,因为这是在 .NET 环境中开发时最好的可扩展解决方案。
使用 Azure 存储! 或任何其他类似的在线云存储解决方案。
- 它确保您的 Web 应用程序与您的文件分开,因此您不必担心将应用程序移动到不同的 Web 环境。
- Web 存储通常比 azure 存储更昂贵(1GB 和大约 3000 次操作(读/写/列表)的总成本约为 0.03 美元。
- 当您在停机时间更为关键的情况下扩展应用程序时,第 1 点也适用于您使用交换/暂存技术。
- Azure 存储负责所谓的Shared Access Tokens (SAS) 的到期
为方便起见,我将在此处仅包含我的代码,因此您不必在 Google 上搜索其余部分
所以在我的情况下,我的所有文件都在数据库中保存为Attachments(当然不是实际文件)。
当有人请求附件时,我会快速检查是否过期,如果过期,我们应该生成一个新的 url。
//where ever you want this to happen, in the controller before going to the client for example
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);//default
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)
{
//CloudConfigurationManager.GetSetting("StorageConnectionString")
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;
}
所以这将产生像这样的网址: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