C# Azure 上传文件错误 指定的 blob 或块内容无效

Posted

技术标签:

【中文标题】C# Azure 上传文件错误 指定的 blob 或块内容无效【英文标题】:C# Azure upload file error The specified blob or block content is invalid 【发布时间】:2017-12-18 01:52:23 【问题描述】:

我正在将文件上传到 Azure 存储。

public class AzureBlob : ICloudBlob

    private string _fileName;
    public string FileName
    
        get => _fileName;
        set
        
            _fileName = value;
            _cloudBlockBlob = CloudBlobContainer.GetBlockBlobReference(value);
        
    
    public CloudBlobContainer CloudBlobContainer  get; set; 
    private CloudBlockBlob _cloudBlockBlob;

    public async Task UploadChunksFromPathAsync(string path, long fileLength)
    
        const int blockSize = 256 * 1024;
        var bytesToUpload = fileLength;
        long bytesUploaded = 0;
        long startPosition = 0;

        var blockIds = new List<string>();
        var index = 0;

        do
        
            var bytesToRead = Math.Min(blockSize, bytesToUpload);
            var blobContents = new byte[bytesToRead];

            using (var fs = new FileStream(path, FileMode.Open))
            
                fs.Position = startPosition;
                fs.Read(blobContents, 0, (int) bytesToRead);
            

            var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(index.ToString("d6")));

            blockIds.Add(blockId);
            await _cloudBlockBlob.PutBlockAsync(blockId, new MemoryStream(blobContents), null);

            bytesUploaded += bytesToRead;
            bytesToUpload -= bytesToRead;
            startPosition += bytesToRead;
            index++;
         while (bytesToUpload > 0);

        await _cloudBlockBlob.PutBlockListAsync(blockIds);   
    

这适用于一个文件上传,多个文件上传一个接一个地调用此方法会在 _cloudBlockBlob.PutBlockListAsync 上引发 400 错误,其中 azure 错误为

指定的 blob 或块内容无效。

如果我删除 _cloudBlockBlob.PutBlockListAsync 上的 await 关键字,它完全可以正常工作。

blockId 的长度都相同。我做错了什么?

编辑

在控制器中调用代码:

[HttpPost]
public async Task<IActionResult> Upload([FromBody] UploadViewModel model)

    var audioBlob = _cloudStorage.GetBlob(CloudStorageType.Audio, model.AudioName);

    await audioBlob.UploadChunksFromPathAsync(model.AudioPath, model.FileLength);

    return Ok();

存储:

public enum CloudStorageType

    Audio,
    Image,


public class AzureStorage : ICloudStorage

    public IDictionary<CloudStorageType, ICloudBlob> CloudBlobs  get; set; 

    public AzureStorage(IConfiguration configuration)
    
        var storageAccount = CloudStorageAccount.Parse(configuration["ConnectionStrings:StorageConnectionString"]);
        var blobClient = storageAccount.CreateCloudBlobClient();

        CloudBlobs = new Dictionary<CloudStorageType, ICloudBlob>();

        foreach (CloudStorageType cloudStorageType in Enum.GetValues(typeof(CloudStorageType)))
        
            CloudBlobs[cloudStorageType] = new AzureBlob(cloudStorageType.ToString().ToLower(), blobClient);
        
    

    public ICloudBlob GetBlob(CloudStorageType cloudStorageType, string fileName)
    
        CloudBlobs[cloudStorageType].FileName = fileName;

        return CloudBlobs[cloudStorageType];
    

Startup.cs

var azureStorage = new AzureStorage(_configuration);

// Add application services.
services.AddSingleton(_configuration);
services.AddSingleton<ICloudStorage>(azureStorage);

【问题讨论】:

能否分享一下调用这个方法的代码? @GauravMantri 完成。我为用户一个接一个地上传(可能有多个)的每个文件上传调用此上传操作。我这样做是为了为每个文件上传显示一个进度条。 您在上传方法之外创建audioBlob 是否有原因(我的意思是UploadChunksFromPathAsync 方法)?每个 audioBlob 实例会代表不同的 blob 名称吗? @GauravMantri 我在我的 startup.cs 中创建了两个 blob。一个包含我的应用程序的所有音频文件的音频 blob 和一个包含音频文件封面图像的图像 blob。这就是它失败的原因吗?我认为这样做比在我的代码中到处创建 blob 更好。 我认为您将blobcontainer 混淆了。根据您的描述,您实际上在启动时创建了 2 个容器(这非常好)。你能分享GetBlob的代码吗?另请分享您如何在您的UploadChunksFromPathAsync 方法中获得_cloudBlockBlob 【参考方案1】:

编辑: 原因实际上是因为下载到一半,blob 被下一个文件覆盖。基本上每次上传都会创建一个新的 blob,这样就不会发生这种情况。

想通了。第一次下载可以正常工作,但第二次下载会抛出错误如果之前的下载尚未完成,因为该块 blob 已在使用下载其他块。

解决方法是为每次下载创建一个新的块 blob,而不是只使用一个。

public async Task UploadChunksFromPathAsync(string path, long fileLength)

    var cloudBlockBlob = CloudBlobContainer.GetBlockBlobReference(FileName);

    const int blockSize = 256 * 1024;
    var bytesToUpload = fileLength;
    long bytesUploaded = 0;
    long startPosition = 0;

    var blockIds = new List<string>();
    var index = 0;

    do
    
        var bytesToRead = Math.Min(blockSize, bytesToUpload);
        var blobContents = new byte[bytesToRead];

        using (var fs = new FileStream(path, FileMode.Open))
        
            fs.Position = startPosition;
            fs.Read(blobContents, 0, (int) bytesToRead);
        

        var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(index.ToString("d6")));

        blockIds.Add(blockId);
        await cloudBlockBlob.PutBlockAsync(blockId, new MemoryStream(blobContents), null);

        bytesUploaded += bytesToRead;
        bytesToUpload -= bytesToRead;
        startPosition += bytesToRead;
        index++;
     while (bytesToUpload > 0);

    await cloudBlockBlob.PutBlockListAsync(blockIds);   

【讨论】:

以上是关于C# Azure 上传文件错误 指定的 blob 或块内容无效的主要内容,如果未能解决你的问题,请参考以下文章

使用 C#(无 JavaScript)直接将 Blazor WebAssembly 文件分块到 Azure Blob 存储

Azure Blob 存储上传错误:(403)禁止

将文件上传到 Azure Blob 存储导致大小为 0

在 Azure Blob 存储中上传文件时出现 InvalidAuthenticationInfo 错误

尝试将生成的 pdf 文件上传到 Azure Blob 存储时出现 404 错误

文件目录无法从 apache camel 上传 azure blob 上的文件