none
InsertOrReplace Operations Broken in Windows Azure Storage Emulator 4.0.0.0

    Question

  • I tracked a problem in my application down to an InsertOrReplace call returning 404s in the emulator when it works properly against the cloud implementation. 

    Running InsertOrReplace with the account name and key credentials works fine.

    Running InsertOrReplace with SAS credentials for the entire table works fine

    Running InsertOrReplace with SAS credentials for a range of partitions throws a 404 every time the specified partition and row does not exist in the table, but is able to replace just fine.

    Running Insert for the same object after a failed InsertOrReplace inserts the object just fine. 

    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Auth;
    using Microsoft.WindowsAzure.Storage.Table;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Azure.NothingWorks
    {
        class BasicTableEntity : TableEntity
        {
    
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                TestRaw();
            }
    
            static void TestRaw()
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse("UseDevelopmentStorage=true");
                //CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                //    "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;" +
                //    "AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;" +
                //    "BlobEndpoint=http://ipv4.fiddler:10000/devstoreaccount1;" +
                //    "QueueEndpoint=http://ipv4.fiddler:10001/devstoreaccount1;" +
                //    "TableEndpoint=http://ipv4.fiddler:10002/devstoreaccount1;");
    
                CloudTableClient tableAdmin = storageAccount.CreateCloudTableClient();
                CloudTable badnessAdmin = tableAdmin.GetTableReference("badness");
    
                BasicTableEntity abt = new BasicTableEntity();
                abt.PartitionKey = "foo";
                abt.RowKey = "bar";
    
                badnessAdmin.DeleteIfExists();
                badnessAdmin.Create();
    
                TableResult tr = new TableResult();
                try
                {
                   tr  = badnessAdmin.Execute(TableOperation.InsertOrReplace(abt));
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
    
                SharedAccessTablePolicy tablePolicy = new SharedAccessTablePolicy();
                tablePolicy.Permissions = SharedAccessTablePermissions.Add | SharedAccessTablePermissions.Delete | SharedAccessTablePermissions.Query | SharedAccessTablePermissions.Update;
                tablePolicy.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(15);
                tablePolicy.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-15);
                
                //String token = barrierAdmin.GetSharedAccessSignature(tablePolicy); //InsertOrReplace works with this policy
                String token = badnessAdmin.GetSharedAccessSignature(tablePolicy, null,  "foo", null, "fooz", null); //But fails with this one.
    
                CloudTable badnessClient = new CloudTable(badnessAdmin.StorageUri, new StorageCredentials(token));
    
                TableResult clientRetrieveResult = badnessClient.Execute(TableOperation.Retrieve<BasicTableEntity>("foo", "bar"));
                TableResult adminRetrieveResult = badnessAdmin.Execute(TableOperation.Retrieve<BasicTableEntity>("foo", "bar"));
    
                TableResult clientWriteResult = new TableResult();
                try
                {
                    BasicTableEntity abt2 = new BasicTableEntity();
                    abt2.PartitionKey = "foo";
                    abt2.RowKey = "bar2";
                    abt2.ETag = "*";
    
                    clientWriteResult = badnessClient.Execute(TableOperation.InsertOrReplace(abt2)); //This line will fail unless the element exists in the table.
                    //clientWriteResult = badnessClient.Execute(TableOperation.Insert(abt2)); //This line would succeed if you ever got to it.  
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }
    }
    

    Tuesday, June 2, 2015 9:55 PM

Answers

  • Hi,

    As you said, you are able to replace but getting error, you may set the 

    IgnoreResourceNotFoundException = true
    in the Constructor and try again.

    Also please make sure, When calling the Insert or Replace Entity operation, you must specify values for the PartitionKey and RowKey system properties. Together, these properties form the primary key and must be unique within the table.

    Both the PartitionKey and RowKey values must be string values; each key value may be up to 64 KB in size. If you are using an integer value for the key value, you should convert the integer to a fixed-width string, because they are canonically sorted. For example, you should convert the value 1 to 0000001 to ensure proper sorting.

    Regards,
    Manu


    Wednesday, June 3, 2015 3:59 PM
    Moderator