【问题标题】:Azure Table Storage Exception: 409 Conflict unexpected?Azure 表存储异常:409 冲突意外?
【发布时间】:2018-07-31 07:15:55
【问题描述】:

我使用的是 WindowsAzure.Storage nuget 包版本 9.0.0。

Install-Package WindowsAzure.Storage -Version 9.0.0

以下代码 (table.CreateIfNotExistsAsync()) 抛出错误:远程服务器返回错误:(409) Conflict。

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 详细信息,我会发现以下消息:指定的表已经存在。

堆栈跟踪:

   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;

我知道我有一些表已经存在并且它们当前没有被删除。为什么我会收到此错误?由于该表确实存在,我希望它能够执行存在性检查并且只返回 true,而不是引发存储异常。

编辑:这就是我创建 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==" />

【问题讨论】:

    标签: azure azure-storage azure-table-storage


    【解决方案1】:

    CreateIfNotExists 正在抛出异常。
    方法 CloudBlobContainer.CreateIfNotExists 或 CloudTable.CreateIfNotExists 的实现发生了变化。

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

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

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

    3. 如果不存在,则调用创建容器或表。

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

    1. 进行调用以创建容器或表(HTTP PUT 请求)。

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

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

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

    【讨论】:

    • 在 8.1.1 中,您说“错误已处理”。通过谁?图书馆?如果确实存在,CreateIfNotExists 不应该抛出一个存储异常供我处理。它应该只返回 false。
    • 如果CreateIfNotExists 在这种情况下抛出,为什么我们需要它!?除了Create,它还能做什么?
    • 情节扭曲:错误与否,ApplicationInsights 将其记录为失败的请求,您会得到漂亮的红色日志!
    • 很烦人。这会导致 Application Insights 中的依赖失败率非常高。
    • 如果您想避免应用程序洞察中丑陋的红色日志,您可以编写自己的 CreateIfNotExists:if (!table.Exists()) { await table.CreateAsync(); }
    【解决方案2】:

    一个不错的解决方法可能是:

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

    【讨论】:

    • 我认为如果您将 CreateAsync 包装在支票中,您可以安全地调用它。 if (!table.Exists()) { await table.CreateAsync(); }
    • @CrhistianRamirez 我认为container.CreateIfNotExists(); 更安全,因为(即使机会可能很小)如果在检查表是否存在之后创建表,那么您将在@987654324 中获得异常@ 你必须自己处理。
    【解决方案3】:

    你是如何创建CloudStorageAccount 对象的?我认为它可能是通过没有 List Tables 权限的 SAS 创建的,因此table.Exists() 始终为每个存储 REST API 设计返回 false,以免将此类信息泄露给未经授权的用户。 table.CreateIfNotExistsAsync() 没有遇到这个问题的原因是该方法直接调用 Create Table REST API 没有事先检查 List Tables,并且故意在 table.CreateIfNotExistsAsync() 方法内部吞下了 409 Conflict 异常(为了实现“create if不存在”功能,因为 409 冲突异常意味着表已经存在,因此该方法可以忽略错误并且什么也不做)。

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

    【讨论】:

    • 什么是 SAS?我添加了有关如何创建 CloudStorageAccount 的代码。
    • table.Exists() 应该返回 true。
    • 我创建了一个拥有所有权限的 SAS。第一次尝试,然后抛出。
    • SAS 是共享访问签名。根据我的更新代码,您使用的是连接字符串而不是 SAS,这很奇怪,因为我无法从我这边重现该问题。
    • @JasonEades 我知道已经有一段时间了,但您可以过滤掉 409。请参阅以下链接:stackoverflow.com/questions/45227439/… & John Gardner 的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-13
    • 2017-03-22
    • 2016-12-05
    • 1970-01-01
    相关资源
    最近更新 更多