如果ETag不匹配,如何使用ETag在插入时抛出异常(除非它是*)

Dav*_* S. 3 c# rest etag azure azure-storage

我需要能够在以下条件下将实体插入到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.");
            }
        }
Run Code Online (Sandbox Code Playgroud)

Dav*_* S. 10

我可能找到了解决方案.如果没有人有更好的答案,会接受这个.

我尝试添加If-Match标题OperationContext,以Etag作为值.这很有效.我认为这是一个自动添加的东西,但显然不是.

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

现在,当使用nullETag时,我可以使用InsertOrReplace,并且它还可以正确检查ETag是否是其他内容.

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

编辑:

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