5

在这些条件下,我需要能够将实体插入到 azure 存储表中:

  • 如果不存在,请插入。
  • 如果存在,但我指定 ETag 为 *,然后替换。
  • 如果它存在,但 ETag 有另一个值,则使用代码 409 或 412 抛出 StorageException。(例如,我会尝试插入我检索到的实体,但同时它已从其他地方更新)

我做了这个简单的程序来测试,但我不知道如何让它工作。它永远不会达到异常。(我认为这是常规的 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.");
    }
}
4

1 回答 1

12

我可能已经找到了解决方案。如果没有人有更好的答案,将接受这一点。

我尝试添加If-Match的标头OperationContext,以 Etag 作为值。这行得通。我认为这是一个自动添加的东西,但显然不是。

testtable.Execute(
  TableOperation.InsertOrReplace(firstRetrieve),
  null,
  new OperationContext {
    UserHeaders = new Dictionary<String, String>
                      {
                        { "If-Match", firstRetrieve.ETag }
                      }
  }
);

现在,当null用作 ETag 时,我可以插入或替换,并且它还可以正确检查 ETag 是否是其他东西。

请注意,如果我*用作 ETag,如果实体不存在,我会收到 404 异常。所以使用null来获得预期的功能。或者只是检测*而不添加标题。

编辑:

警告:如果您想插入一个新项目 (ETag == null),但如果它已经存在,但仍希望获得异常代码 409 冲突,则必须使用Insert操作而不是InsertOrReplace操作。

于 2013-07-05T12:24:47.107 回答