18

我对 Windows Azure 开发非常陌生,并且需要将一些数据存储在 Windows azure 存储表中。

该表的存在实际上只是为了为位于 azure 存储驱动器上的某些文件提供快速查找机制。

因此,我计划在应用程序启动时填充此表(即在 Web 应用程序全局应用程序启动时)

与其尝试维护此表以进行更改,不如尝试在应用程序未运行时驱动器可能发生的更改。或者由于这个驱动器只是一个资源的 vhd,我们可能偶尔会上传一个新的 vhd。

因此,而不是尝试维护这一点的麻烦。在每次应用程序启动时重建该表就足够了。

我开始整理一些代码来检查表是否已经存在,如果确实删除它,然后重新创建一个新表。

var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorage"].ConnectionString);
var tableClient = storageAccount.CreateCloudTableClient();
var rmsTable = tableClient.GetTableReference("ResourceManagerStorage");
rmsTable.DeleteIfExists();
rmsTable.Create();

我原以为这行不通。我收到以下错误:

The remote server returned an error: (409) Conflict. 

HTTP/1.1 409 Conflict
Cache-Control: no-cache
Transfer-Encoding: chunked
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: c6baf92e-de47-4a6d-82b3-4faec637a98c
x-ms-version: 2012-02-12
Date: Tue, 19 Mar 2013 17:26:25 GMT

166
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code>TableBeingDeleted</code>
  <message xml:lang="en-US">The specified table is being deleted. Try operation later.
RequestId:c6baf92e-de47-4a6d-82b3-4faec637a98c
Time:2013-03-19T17:26:26.2612698Z</message>
</error>
0

这样做的正确方法是什么?是否有可以订阅的事件让您知道表何时被删除?关于实现这一点的最佳方式的任何其他建议?

4

2 回答 2

29

来自MSDN:“请注意,删除表可能需要至少 40 秒才能完成。如果在删除表时尝试对表执行操作,服务将返回状态代码 409(冲突),并附加错误信息表明该表正在被删除。”

处理此问题的唯一方法是创建一个具有不同名称的表。这可以像在您的姓名后附加时间戳或 GUID 一样简单。只是要小心清理你的垃圾。

于 2013-03-19T19:39:41.343 回答
15

如果您需要使用相同的表名,您可以使用扩展方法:

public static class StorageExtensions
{
    #region Non-async

    public static bool SafeCreateIfNotExists(this CloudTable table, TimeSpan? timeout, TableRequestOptions requestOptions = null, OperationContext operationContext = null)
    {
        Stopwatch sw = Stopwatch.StartNew();
        if (timeout == null) timeout = TimeSpan.FromSeconds(41); // Assuming 40 seconds max time, and then some.
        do
        {
            if (sw.Elapsed > timeout.Value) throw new TimeoutException("Table was not deleted within the timeout.");

            try
            {
                return table.CreateIfNotExists(requestOptions, operationContext);
            }
            catch (StorageException e) when(IsTableBeingDeleted(e))
            {
                Thread.Sleep(1000);
            }
        } while (true);
    }

    #endregion

    #region Async

    public static async Task<bool> SafeCreateIfNotExistsAsync(this CloudTable table, TimeSpan? timeout, TableRequestOptions requestOptions = null, OperationContext operationContext = null, CancellationToken cancellationToken = default)
    {
        Stopwatch sw = Stopwatch.StartNew();
        if (timeout == null) timeout = TimeSpan.FromSeconds(41); // Assuming 40 seconds max time, and then some.
        do
        {
            if (sw.Elapsed > timeout.Value) throw new TimeoutException("Table was not deleted within the timeout.");

            try
            {
                return await table.CreateIfNotExistsAsync(requestOptions, operationContext, cancellationToken).ConfigureAwait(false);
            }
            catch (StorageException e) when(IsTableBeingDeleted(e))
            {
                // The table is currently being deleted. Try again until it works.
                await Task.Delay(1000);
            }
        } while (true);
    }

    #endregion

    private static bool IsTableBeingDeleted(StorageException e)
    {
        return
            e.RequestInformation.HttpStatusCode == 409
            &&
            e.RequestInformation.ExtendedErrorInformation.ErrorCode.Equals( TableErrorCodeStrings.TableBeingDeleted );
    }
}

警告!使用这种方法时要小心,因为它会阻塞线程。如果第三方服务 (Azure) 不断产生这些错误,它可能会进入死循环。造成这种情况的原因可能是表锁定、订阅到期、服务不可用等。

于 2014-03-05T10:27:31.913 回答