我尝试在服务总线主题触发 Azure 函数中使用 blob url 下载 blob,但出现以下错误:
Status: 404 (The specified blob does not exist.)
ErrorCode: BlobNotFound
Content:
<?xml version="1.0" encoding="utf-8"?><Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.
</Message></Error>
下面是我的 Startup.cs 文件:
[assembly: FunctionsStartup(typeof(Startup))]
namespace Emails.Dispatcher
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton(x =>
new BlobServiceClient(connectionString: Environment.GetEnvironmentVariable("AzureWebJobsStorage")));
builder.Services.AddSingleton<IBlobService, BlobService>();
builder.Services.AddLogging();
builder.Services.AddHttpClient();
builder.AddHelpers();
builder.Services.AddWorkers();
}
}
}
Blob 服务:
public class BlobService : IBlobService
{
private readonly BlobServiceClient _blobServiceClient;
public BlobService(BlobServiceClient blobServiceClient)
{
this._blobServiceClient = blobServiceClient;
}
public async Task<byte[]> DownloadAsync(string containerName, string fileUri)
{
var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
var blobClient = containerClient.GetBlobClient(fileUri);
using (var ms = new MemoryStream())
{
await blobClient.DownloadStreamingAsync();
return ms.ToArray();
}
}
public async Task<BlobDto> UploadAsync(string containerName, string filename, string content)
{
var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
var blobClient = containerClient.GetBlobClient(filename);
var bytes = Encoding.UTF8.GetBytes(content);
await using var memoryStream = new MemoryStream(bytes);
await blobClient.UploadAsync(content);
return new BlobDto
{
Uri = blobClient.Uri,
Name = blobClient.Name
};
}
}
public interface IBlobService
{
Task<BlobDto> UploadAsync(string containerName, string filename, string content);
Task<byte[]> DownloadAsync(string containerName, string fileUri);
}
实际上此服务正在接收完整的 blob url (即 https://{storage-url}.blob.core.windows.net/{container-name}/files/unzip/691ec307-7c2b-4aaa-8f75-8742c9faa9f5/ 1615015726/{文件名}.pdf).
我在这里错过了什么吗?
我可以借助 CloudBlockBlob 的 Uri 和 Name 属性来下载 blob 文件。如下图:
public async Task<byte[]> DownloadAsync(string containerName, string fileUri)
{
var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
var blobUri = new System.Uri(fileUri);
var name = new CloudBlockBlob(blobUri).Name;
var blobClient = containerClient.GetBlobClient(name);
var response = await blobClient.DownloadStreamingAsync();
using MemoryStream ms = new MemoryStream();
await response.Value.Content.CopyToAsync(ms);
ms.Position = 0;
return ms.ToArray();
}
问题出在以下代码行:
var blobClient = containerClient.GetBlobClient(fileUri);
使用
BlobClient
和 ContainerClient
创建
GetBlobClient
时,您只需提供 blob 的名称,而不是整个 URL。
要解决此问题,只需传递 blob 名称即可。
您的 blob 名称中可能有未分配的字符串。
有效的解决方法:将段号替换为文件容器段号,并使用替换来修复未知的文件名字符。
CloudBlobDirectory dira = Container.GetDirectoryReference(string.Empty);
var rootDirFolders = dira.ListBlobsSegmentedAsync(true, BlobListingDetails.Metadata, null, null, null, null).Result.Results;
foreach(rootDirFolders 中的 var blob)
{
var blockBlob = Container.GetBlockBlobReference(blob.StorageUri.PrimaryUri.Segments[2].Replace("%20", " "));
var blockBlobRecent = blockBlob.Name.Contains(formatdateValue); //filters blobs by date. Standard practice is that each blob has date in the name. Avoid using Modified date as filter
if (blockBlobRecent)
{
string localPath = DownloadPath + blob.StorageUri.PrimaryUri.Segments[2].Replace("%20", " ");
string localPathfinal = localPath.Replace("%20", " ");
await blockBlob.DownloadToFileAsync(localPathfinal, FileMode.Create).ConfigureAwait(false);
}
else
{
//do nothing
}
}