How to use ETag to throw exception on insert if ETag doesn't match (except when it's *)

孤街醉人 提交于 2021-02-18 12:59:27

问题


I need to be able to insert an entity to an azure storage table under these conditions:

  • if it doesn't exist, insert.
  • if it exists, but I specify ETag to be *, then replace.
  • if it exists, but ETag has another value, then throw StorageException with code 409 or 412. (for example I would try to insert an entity I have retrieved, but it has been updated from elsewhere in the meantime)

I made this simple program to test, but I can't figure out how to get this to work. it never reaches the exception. (I thought this was regular ETag behavior requirements).

Note that if I use Insert operation instead of InsertOrReplace I get an exception even if ETag has an unchanged value.

        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.");
            }
        }

回答1:


I may have found a solution. Will accept this if nobody has a better answer.

I tried to add If-Match header of the OperationContext, with the Etag as the value. This worked. I thought this was an automatically added thing, but apparently not.

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

Now, when using null as ETag, I can InsertOrReplace, and it also properly checks ETag if it's something else.

Note that if I use * as ETag, I get a 404 exception if the entity doesn't exist. So use null to get the intended functionality. Or just detect * and don't add the header.

EDIT:

Caveat: If you'd want to insert a new item (ETag == null) but still want to get an exception code 409 conflict if it already exists, you must use the Insert operation instead of the InsertOrReplace operation.



来源:https://stackoverflow.com/questions/17487965/how-to-use-etag-to-throw-exception-on-insert-if-etag-doesnt-match-except-when

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!