Azure Table 存储异常:409 意外冲突?

Azure Table Storage Exception: 409 Conflict unexpected?

我正在使用 WindowsAzure.Storage nuget 包版本 9.0.0。

Install-Package WindowsAzure.Storage -Version 9.0.0

以下代码 (table.CreateIfNotExistsAsync()) 引发错误:远程服务器 returned 错误:(409) 冲突。

CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference(tableName);
try
{
    if (await table.CreateIfNotExistsAsync())
    {
        log.Info(string.Format("Created Table named: {0}", tableName));
    }
}
catch (StorageException)
{
    log.Error("If you are running with the default configuration please make sure you have started the storage emulator. Press the Windows key and type Azure Storage to select and run it from the list of applications - then restart the sample.");
    throw;
}

return table;

如果我检查 StorageException 的详细信息,我会发现这条消息:指定的 table 已经存在。

堆栈跟踪:

   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult result) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs:line 57

这段代码工作正常:

CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference(tableName);

try
{
    //if (await table.CreateIfNotExistsAsync())
    //{
    //    log.Info(string.Format("Created Table named: {0}", tableName));
    //}

    if (!table.Exists())
    {
        await table.CreateAsync();

        log.Info(string.Format("Created Table named: {0}", tableName));
    }
}
catch (StorageException)
{
    log.Error("If you are running with the default configuration please make sure you have started the storage emulator. Press the Windows key and type Azure Storage to select and run it from the list of applications - then restart the sample.");
    throw;
}

return table;

我知道我有 tables 已经存在并且它们当前没有被删除。为什么会出现此错误?由于 table 确实存在,我希望它能够执行存在性检查并且 return 为真,而不是抛出存储异常。

编辑: 这就是我创建 CloudStorageAccount 的方式

public static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString)
{
    CloudStorageAccount storageAccount;
    try
    {
        storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    }
    catch (FormatException fe)
    {
        log.Error("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the application.", fe);
        throw;
    }
    catch (ArgumentException ae)
    {
        log.Error("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample.", ae);
        throw;
    }

    return storageAccount;
}

存储连接字符串如下所示:

<add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=something;AccountKey=somekeygoeshere==" />

您是如何创建 CloudStorageAccount 对象的?我认为它可能是通过没有 List Tables 权限的 SAS 创建的,因此 table.Exists() 始终 returns false 每个存储 REST API 设计,以免泄漏此类未经授权的用户的信息。 table.CreateIfNotExistsAsync()没有遇到这个问题的原因是方法直接调用了CreateTableRESTAPI,没有事先检查ListTables,409 Conflict异常被吞掉了故意在 table.CreateIfNotExistsAsync() 方法中(为了实现 "create if not exists" 功能,因为 409 冲突异常意味着 table 已经存在,所以该方法可以忽略错误而不做任何事情)。

如果我的上述理论适用于您的情况,请使用具有 List Table 权限的 SAS 而不是现有的 SAS,或者直接使用共享帐户密钥创建 CloudStorageAccount 对象。

CreateIfNotExists 抛出异常。
CloudBlobContainer.CreateIfNotExistsCloudTable.CreateIfNotExists.

方法的实现发生了变化

7.1.2 存储客户端库中的实现如下:

  1. 调用以检查存储容器或 table 是否存在(HTTP HEAD 请求)。

  2. 如果它存在什么也不做。

  3. 如果不存在则调用创建容器或table.

在存储客户端库8.1.1中实现如下:

  1. 调用创建容器或table(HTTP PUT 请求)。

  2. 如果由于容器或 table 已经存在而返回错误 (HTTP 409),则什么也不做。错误已处理。

  3. 如果容器或 table 不存在,则创建会成功。

我检查了 9.0,该行为仍然存在

一个不错的解决方法是:

if (!container.Exists())
        {
            container.CreateIfNotExists();
        }