You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C# Azure存储库通过ETag删除Blob历史版本失败,求解决方案

问题描述

使用Azure Functions、Azure Blob存储和React前端构建文件管理工具,已实现Blob及其历史版本详情展示,可获取当前版本与历史版本的VersionId和ETag。因大量大文件历史版本导致存储成本过高,需添加删除Blob历史版本功能,当前存储账户已启用软删除和版本管理。

现有代码可通过ETag匹配成功删除当前版本,但使用有效历史版本ETag时删除失败,返回412 ConditionNotMet错误。

现有代码

// Get a reference to a container where the blob is located
BlobContainerClient containerClient = _blobService.GetBlobContainerClient(deleteMessage!.ContainerName);

Dictionary<string, bool> deletedItemStatus = [];

// Get a reference to the blob you want to delete
BlobClient blobClient = containerClient.GetBlobClient(deleteMessage.Path);

foreach(var eTag in deleteMessage.ETags)
{
    // TODO - this works perfectly well if we delete the current version using its ETag - but we cant delete previous versions...
    deletedItemStatus.Add(eTag, await blobClient.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots, new BlobRequestConditions { IfMatch = new ETag(eTag) }, cancellationToken: token));
}

var deletedOK = deletedItemStatus.All(r => r.Value == true);

_logger.LogInformation("File Delete Operation completed successfully? : {Status}", deletedOK);

return deletedOK;

错误日志

[2024-02-19T15:35:44.696Z] Status: 412 (The condition specified using HTTP conditional header(s) is not met.)
[2024-02-19T15:35:44.699Z]
[2024-02-19T15:35:44.701Z] ErrorCode: ConditionNotMet
[2024-02-19T15:35:44.702Z] Headers:
[2024-02-19T15:35:44.703Z]
[2024-02-19T15:35:44.704Z] Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0

确认历史版本ETag有效(刚获取且可用于删除当前版本),但问题仍存在,需解决思路。


解决思路与代码修改

问题根源

BlobClient.DeleteIfExistsAsync默认操作的是Blob的当前版本,即使指定历史版本的ETag,该API也无法定位到历史版本进行删除。历史版本是独立的资源,需要使用BlobVersionClient来单独操作。另外,DeleteSnapshotsOption.IncludeSnapshots是针对快照功能的,和版本管理无关,此处无需使用。

解决方案步骤

  1. 针对每个要删除的历史版本,通过VersionId或ETag定位到具体版本
  2. 创建对应版本的BlobVersionClient实例
  3. 使用BlobVersionClient.DeleteIfExistsAsync执行删除操作,可保留ETag匹配条件确保操作的原子性

修改后的代码示例

BlobContainerClient containerClient = _blobService.GetBlobContainerClient(deleteMessage!.ContainerName);
Dictionary<string, bool> deletedItemStatus = [];

// 获取该Blob的所有版本列表(用于匹配ETag对应的VersionId)
var blobVersions = containerClient.GetBlobVersionsAsync(deleteMessage.Path);

foreach(var eTag in deleteMessage.ETags)
{
    // 查找对应ETag的版本
    var targetVersion = await blobVersions.FirstOrDefaultAsync(v => v.Properties.ETag.ToString() == eTag);
    if(targetVersion != null)
    {
        // 创建对应版本的BlobVersionClient
        BlobVersionClient versionClient = containerClient.GetBlobVersionClient(deleteMessage.Path, targetVersion.VersionId);
        // 执行删除操作,保留IfMatch条件验证ETag
        bool deleted = await versionClient.DeleteIfExistsAsync(
            conditions: new BlobRequestConditions { IfMatch = new ETag(eTag) }, 
            cancellationToken: token);
        deletedItemStatus.Add(eTag, deleted);
    }
    else
    {
        // 未找到对应ETag的版本,标记为删除失败
        deletedItemStatus.Add(eTag, false);
    }
}

var deletedOK = deletedItemStatus.All(r => r.Value == true);
_logger.LogInformation("File Delete Operation completed successfully? : {Status}", deletedOK);
return deletedOK;

额外注意事项

  • 版本与快照的区别:启用版本管理后生成的历史版本,和快照是不同的资源,不要混淆两者的操作API
  • SDK版本:确保使用最新版的Azure.Storage.Blobs NuGet包,旧版本可能对BlobVersionClient的支持不完善
  • 权限验证:确保Azure Functions使用的身份(如托管标识)拥有Storage Blob Data Contributor或足够的权限删除Blob版本

内容的提问来源于stack exchange,提问作者Ian Robertson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:03:27