我是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
正确的做法是什么?是否有一个可以订阅的事件让您知道表何时被删除?关于实现这一点的最佳方式有其他建议吗?
From MSDN: "注意,删除表可能需要至少40秒才能完成。如果在删除表时尝试对表进行操作,则服务返回状态码409(冲突),并附带指示表正在被删除的附加错误信息。"
处理这个问题的唯一方法是用不同的名称创建一个表。这就像在您的名字后面附加时间戳或GUID一样简单。注意清理你的垃圾。
如果需要使用相同的表名,可以使用扩展方法:
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)继续生成这些错误,它可能会进入死循环。原因可能是表锁定、订阅过期、服务不可用等。