当GenerateIfNotExistsCondition用于目标时,为什么StartCopyAsync()抛出409冲突?

时间:2017-06-15 23:57:01

标签: c# azure azure-storage azure-storage-blobs

如果目标帐户不存在,我想将blob复制到另一个存储帐户。但我必须误读StartCopyAsyncGenerateIfNot​Exists​Condition上的文档,因为我认为我可以在一次调用中完成此操作(无需在另一个调用中检查目标存在),具体如下:

    await _targetClient.StartCopyAsync(
        _schemaBlob, 
        null, 
        _schemaBlob.Name, 
        AccessCondition.GenerateIfNotExistsCondition(), 
        null, 
        ContainerName, 
        cancellationToken);

但如果目标blob存在,它会抛出409 Conflict。这不是AccessCondition.GenerateIfNotExistsCondition()参数的要点,以确保在blob存在时操作不会执行任何操作吗?

如何正确做到?

1 个答案:

答案 0 :(得分:2)

  

但如果目标blob存在,它会抛出409冲突。不是说AccessCondition.GenerateIfNotExistsCondition()参数的重点是确保当blob存在时操作不会执行任何操作吗?

在Azure存储服务端,它将不执行任何操作,只返回409状态代码。在客户端,如果返回码不等于200,则抛出异常。我建议你在代码中添加一个try-catch blob,并在catch blob中不执行任何操作。

try
{
    //put your copy code here
}
catch (StorageException ex)
{
    //If the exception is 409, just skip the exception
    if (!ex.Message.Contains("409"))
    {
        throw ex;
    }
}

否则,您可以在执行复制命令之前检查目标blob是否存在。

if (targetBlob.Exists())
{
    //do the copy here
}
  

将此参数保留为null并初始化为我所做的行为是相同的。

它可能包含代码中的一些错误。有2个AccessCondition,一个用于源blob,另一个用于目标blob。这是一个示例方法。如果将目标AccessCondition的值更改为null。目标blob将被源blob覆盖。

public static async void CopyBlob(Uri sourceBlob, CloudBlockBlob targetBlob, System.Threading.CancellationToken cancellationToken)
{
   string text  = await targetBlob.StartCopyAsync(
       sourceBlob,
       //Source blob access condition, it will check whether the source is exist. If source doesn't exist, a exeception will throw.
       Access​Condition.GenerateIfExistsCondition(),
       //Target blob access condition, it will check whether the target is exist. If target blob exist, 409 error will occur.
       AccessCondition.GenerateIfNotExistsCondition(),
       null,
       null,
       cancellationToken);
}

这是我的测试代码。请注意,如果源容器是私有的,则需要使用SAS提供源blob URI到StartCopyAsync方法的第一个参数。

Uri sourceUri = new Uri("Put your source blob uri with SAS");

string targetConnectionString = "target blob connectionString ";
CloudStorageAccount targetStorageAccount = CloudStorageAccount.Parse(targetConnectionString);
// Create the blob client.
CloudBlobClient targetBlobClient = targetStorageAccount.CreateCloudBlobClient();

CloudBlobContainer targetContainer = targetBlobClient.GetContainerReference("mycontainer2");
CloudBlockBlob targetBlob = targetContainer.GetBlockBlobReference("text1.txt");

CopyBblob(sourceUri, targetBlob, new System.Threading.CancellationToken());