如果 ETag 不匹配,如何使用 ETag 在插入时抛出异常(除非它是 *)
Posted
技术标签:
【中文标题】如果 ETag 不匹配,如何使用 ETag 在插入时抛出异常(除非它是 *)【英文标题】:How to use ETag to throw exception on insert if ETag doesn't match (except when it's *) 【发布时间】:2013-07-03 12:03:49 【问题描述】:我需要能够在这些条件下将实体插入到 Azure 存储表中:
如果不存在,则插入。 如果存在,但我指定ETag为*,则替换。 如果它存在,但 ETag 有另一个值,则抛出 StorageException 代码为 409 或 412。(例如,我会尝试插入我检索到的实体,但同时它已从其他地方更新)我制作了这个简单的程序进行测试,但我不知道如何让它工作。它永远不会达到异常。 (我认为这是常规的 ETag 行为要求)。
请注意,如果我使用 Insert 操作而不是 InsertOrReplace,即使 ETag 的值未更改,也会出现异常。
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnString);
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
tableClient.RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 10);
var testtable = tableClient.GetTableReference("davidstesttable");
testtable.CreateIfNotExists();
//insert first entity
var newentity = new DynamicTableEntity("idunno", String.Empty, "*", new Dictionary<string, EntityProperty> "testprop", new EntityProperty("testval") );
Msg("insert initial entity");
testtable.Execute(TableOperation.InsertOrReplace(newentity));
Msg("inserted");
Msg("retrieving");
TableResult tableResult = testtable.Execute(TableOperation.Retrieve("idunno", String.Empty));
DynamicTableEntity firstRetrieve = (DynamicTableEntity)tableResult.Result;
Msg("retrieved. etag: " + firstRetrieve.ETag);
Msg("inserting the initial entity again to change the ETag in the table");
testtable.Execute(TableOperation.InsertOrReplace(newentity));
Msg("inserted");
Msg("retrieving");
TableResult tableResult2 = testtable.Execute(TableOperation.Retrieve("idunno", String.Empty));
DynamicTableEntity secondRetrieve = (DynamicTableEntity)tableResult2.Result;
Msg("retrieved. etag: " + secondRetrieve.ETag);
if(firstRetrieve.ETag != secondRetrieve.ETag)
Msg("confirmed entity in table now has different etag");
Msg("inserting the first retrieved. (etags should not match now, expecting StorageException)");
try
//If I use Insert operation instead of InsertOrReplace, I do get the exception,
//but I tested with this and then I get the exception even if the ETag is unchanged or * !
testtable.Execute(TableOperation.InsertOrReplace(firstRetrieve));
Msg("hmm should not have reached here!");
catch (StorageException e)
if(e.RequestInformation.HttpStatusCode == 409 || e.RequestInformation.HttpStatusCode == 412)
Msg("got exception as expected because of the mismatching ETag.");
【问题讨论】:
如果您的实体已经有一个 ETag,那么您就知道它存在。为什么不使用Update
而不是InsertOrReplace
?
【参考方案1】:
我可能已经找到了解决方案。如果没有人有更好的答案,我会接受。
我尝试添加OperationContext
的If-Match
标头,并将Etag 作为值。这行得通。我以为这是自动添加的东西,但显然不是。
testtable.Execute(
TableOperation.InsertOrReplace(firstRetrieve),
null,
new OperationContext
UserHeaders = new Dictionary<String, String>
"If-Match", firstRetrieve.ETag
);
现在,当使用null
作为 ETag 时,我可以 InsertOrReplace,并且它还可以正确检查 ETag 是否是其他东西。
请注意,如果我使用 *
作为 ETag,如果实体不存在,我会收到 404 异常。所以使用null
来获得预期的功能。或者只检测*
而不添加标题。
编辑:
警告:如果您想插入一个新项目 (ETag == null
),但如果它已经存在,但仍希望获得异常代码 409 冲突,则必须使用 Insert
操作而不是 @ 987654330@操作。
【讨论】:
以上是关于如果 ETag 不匹配,如何使用 ETag 在插入时抛出异常(除非它是 *)的主要内容,如果未能解决你的问题,请参考以下文章