I need to be able to insert an entity to an azure storage table under these conditions:
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.");
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With