locked
Cannot find any sample code of Entity Group Transaction via REST RRS feed

  • Question

  • The only web page I can find is http://msdn.microsoft.com/en-us/library/dd894038.aspx but it is not very clear. I am looking for any sample code in C# to generate such a REST request. I searched internet, cannot find any resource. I looked up some books, all books I found says "due to the complexity, please to go http://msdn.microsoft.com/en-us/library/dd894038.aspx for more detail". 

    I can easily find single entity azure table REST sample code or Entity Group Transaction in StorageClient API. However, maybe it is too complex, no one contribute the Entity Group Transaction via REST.

     

    Can any one tell me where I can find the sample code? The MSDN explanation is not clear to me.

     

    Thanks

    Sunday, March 13, 2011 6:44 AM

Answers

  • private String CreateAuthorizationHeader(String canonicalizedString)
    {
    	String signature = string.Empty;
    	using (HMACSHA256 hmacSha256 = new HMACSHA256(AzureStorageConstants.Key))
    	{
    		Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
    		signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
    	}
    
    	String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", AzureStorageConstants.SharedKeyAuthorizationScheme, AzureStorageConstants.Account, signature);
    
    	return authorizationHeader;
    }
    
    
    • Marked as answer by Brad Calder Monday, March 12, 2012 9:20 AM
    Wednesday, May 4, 2011 4:54 AM
    Answerer

All replies

  • The following is an example of an entity group transaction using REST. The code inserts a couple of records in a table named "Novel" in Azure storage. This runs against cloud storage but I have not tried it against development storage. I'm not sure if entity group transactions are implemented with development storage. I am sure the code could be improved significantly - but this was a one-off example just to see how it works.

    private void ExecuteBatch(String tableName)
    {
    	String requestMethod = "POST";
    	String urlPath = "$batch";
    	String msVersion = "2009-09-19";
    	String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
    	String contentMD5 = String.Empty;
    	String contentType = "multipart/mixed; boundary=batch_26096be3-6b4e-4b9b-a145-b6d74fddc2b8"; //"application/atom+xml";
    	String canonicalizedResource = String.Format("/{0}/{1}", AzureStorageConstants.Account, urlPath);
    	String stringToSign = String.Format("{0}\n{1}\n{2}\n{3}\n{4}", requestMethod, contentMD5, contentType, dateInRfc1123Format, canonicalizedResource);
    	String authorizationHeader = CreateAuthorizationHeader(stringToSign);
    
    	UTF8Encoding utf8Encoding = new UTF8Encoding();
    	Byte[] content = utf8Encoding.GetBytes(GetRequestBodyBatch(AzureStorageConstants.TableEndPoint, tableName));
    
    	Uri uri = new Uri(AzureStorageConstants.TableEndPoint + urlPath);
    	HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    	request.Accept = "application/atom+xml,application/xml";
    	request.ContentLength = content.Length;
    	request.ContentType = contentType;
    	request.Method = requestMethod;
    	request.Headers.Add("x-ms-date", dateInRfc1123Format);
    	request.Headers.Add("x-ms-version", msVersion);
    	request.Headers.Add("Authorization", authorizationHeader);
    	request.Headers.Add("Accept-Charset", "UTF-8");
    
    	request.Headers.Add("DataServiceVersion", "1.0;NetFx");
    	request.Headers.Add("MaxDataServiceVersion", "1.0;NetFx");
    
    	using (Stream requestStream = request.GetRequestStream())
    	{
    		requestStream.Write(content, 0, content.Length);
    	}
    
    	using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    	{
    		Stream dataStream = response.GetResponseStream();
    		using (StreamReader reader = new StreamReader(dataStream))
    		{
    			String responseFromServer = reader.ReadToEnd();
    		}
    	}
    }
    
    
    private String GetRequestBodyBatch(string tableEndpoint, String tableName)
    {
    	String postString = String.Format("POST {0}{1} HTTP/1.1", tableEndpoint, tableName);
    	String entry1 = GetRequestContentInsertXml("An Author", "Third Book");
    	String entry2 = GetRequestContentInsertXml("An Author", "Fourth Book");
    
    	StringBuilder batch = new StringBuilder("--batch_26096be3-6b4e-4b9b-a145-b6d74fddc2b8");
    	batch.Append(Environment.NewLine);
    	batch.AppendLine("Content-Type: multipart/mixed; boundary=changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8");
    
    	batch.Append(Environment.NewLine);
    	batch.AppendLine("--changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8");
    	batch.AppendLine("Content-Type: application/http");
    	batch.AppendLine("Content-Transfer-Encoding: binary");
    
    	batch.Append(Environment.NewLine);
    	batch.AppendLine(postString);
    	batch.AppendLine("Content-ID: 1");
    	batch.AppendLine("Content-Type: application/atom+xml;type=entry");
    	batch.AppendLine("Content-Length: " + entry1.Length);
    
    	batch.Append(Environment.NewLine);
    	batch.AppendLine(entry1);
    	batch.AppendLine("--changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8");
    	batch.AppendLine("Content-Type: application/http");
    	batch.AppendLine("Content-Transfer-Encoding: binary");
    
    	batch.Append(Environment.NewLine);
    	batch.AppendLine(postString);
    	batch.AppendLine("Content-ID: 2");
    	batch.AppendLine("Content-Type: application/atom+xml;type=entry");
    	batch.AppendLine("Content-Length: " + entry2.Length);
    
    	batch.Append(Environment.NewLine);
    	batch.AppendLine(entry2);
    	batch.AppendLine("--changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8--");
    	batch.AppendLine("--batch_26096be3-6b4e-4b9b-a145-b6d74fddc2b8--");
    
    	String requestBodyBatch = batch.ToString();
    	return requestBodyBatch;
    }
    
    private String GetRequestContentInsertXml(String artist, String title)
    {
    	String defaultNameSpace = "http://www.w3.org/2005/Atom";
    	String dataservicesNameSpace = "http://schemas.microsoft.com/ado/2007/08/dataservices";
    	String metadataNameSpace = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
    
    	XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
    	xmlWriterSettings.OmitXmlDeclaration = false;
    	xmlWriterSettings.Encoding = Encoding.UTF8;
    
    	StringBuilder entry = new StringBuilder();
    	using (XmlWriter xmlWriter = XmlWriter.Create(entry))
    	{
    		xmlWriter.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    		xmlWriter.WriteWhitespace("\n");
    		xmlWriter.WriteStartElement("entry", defaultNameSpace);
    		xmlWriter.WriteAttributeString("xmlns", "d", null, dataservicesNameSpace);
    		xmlWriter.WriteAttributeString("xmlns", "m", null, metadataNameSpace);
    		xmlWriter.WriteElementString("title", null);
    		xmlWriter.WriteElementString("updated", String.Format("{0:o}", DateTime.UtcNow));
    		xmlWriter.WriteStartElement("author");
    		xmlWriter.WriteElementString("name", null);
    		xmlWriter.WriteEndElement();
    		xmlWriter.WriteElementString("id", null);
    		xmlWriter.WriteStartElement("content");
    		xmlWriter.WriteAttributeString("type", "application/xml");
    		xmlWriter.WriteStartElement("properties", metadataNameSpace);
    		xmlWriter.WriteElementString("PartitionKey", dataservicesNameSpace, artist);
    		xmlWriter.WriteElementString("RowKey", dataservicesNameSpace, title);
    		xmlWriter.WriteElementString("Artist", dataservicesNameSpace, artist);
    		xmlWriter.WriteElementString("Title", dataservicesNameSpace, title);
    		xmlWriter.WriteEndElement();
    		xmlWriter.WriteEndElement();
    		xmlWriter.WriteEndElement();
    		xmlWriter.Close();
    	}
    	String requestContent = entry.ToString();
    	return requestContent;
    }
    
    

    AzureStorageConstants.Account = ACCOUNT.
    AzureStorageConstants.TableEndpoint = http://ACCOUNT.table.core.windows.net/

    The following is the request as seen by Fiddler:

    POST http://ACCOUNT.table.core.windows.net/$batch HTTP/1.1
    Accept: application/atom+xml,application/xml
    Content-Type: multipart/mixed; boundary=batch_26096be3-6b4e-4b9b-a145-b6d74fddc2b8
    x-ms-date: Sun, 13 Mar 2011 07:29:02 GMT
    x-ms-version: 2009-09-19
    Authorization: SharedKey ACCOUNT:blahblahblah=
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Host: ACCOUNT.table.core.windows.net
    Content-Length: 1804
    Expect: 100-continue
    Connection: Keep-Alive

    --batch_26096be3-6b4e-4b9b-a145-b6d74fddc2b8
    Content-Type: multipart/mixed; boundary=changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8

    --changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8
    Content-Type: application/http
    Content-Transfer-Encoding: binary

    POST http://ACCOUNT.table.core.windows.net/Novel HTTP/1.1
    Content-ID: 1
    Content-Type: application/atom+xml;type=entry
    Content-Length: 518

    <?xml version="1.0" encoding="UTF-8"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom"><title /><updated>2011-03-13T07:29:02.8378906Z</updated><author><name /></author><id /><content type="application/xml"><m:properties><d:PartitionKey>An Author</d:PartitionKey><d:RowKey>Third Book</d:RowKey><d:Artist>An Author</d:Artist><d:Title>Third Book</d:Title></m:properties></content></entry>
    --changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8
    Content-Type: application/http
    Content-Transfer-Encoding: binary

    POST http://ACCOUNT.table.core.windows.net/Novel HTTP/1.1
    Content-ID: 2
    Content-Type: application/atom+xml;type=entry
    Content-Length: 520

    <?xml version="1.0" encoding="UTF-8"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom"><title /><updated>2011-03-13T07:29:02.8388671Z</updated><author><name /></author><id /><content type="application/xml"><m:properties><d:PartitionKey>An Author</d:PartitionKey><d:RowKey>Fourth Book</d:RowKey><d:Artist>An Author</d:Artist><d:Title>Fourth Book</d:Title></m:properties></content></entry>
    --changeset_26096be3-6b4e-4b9b-a145-b6d74fddc2b8--
    --batch_26096be3-6b4e-4b9b-a145-b6d74fddc2b8--

    The following is the response as seen by Fiddler:

    HTTP/1.1 202 Accepted
    Cache-Control: no-cache
    Content-Type: multipart/mixed; boundary=batchresponse_7c5c9678-0b18-4363-93f9-a55d9e30c2b8
    Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 7e2a77ce-ab63-4c55-ae0b-1d9b0d0dd801
    x-ms-version: 2009-09-19
    Date: Sun, 13 Mar 2011 07:28:53 GMT
    Content-Length: 3387

    --batchresponse_7c5c9678-0b18-4363-93f9-a55d9e30c2b8
    Content-Type: multipart/mixed; boundary=changesetresponse_3f3997db-60a3-4a0f-99a1-5dbe5e1253c3

    --changesetresponse_3f3997db-60a3-4a0f-99a1-5dbe5e1253c3
    Content-Type: application/http
    Content-Transfer-Encoding: binary

    HTTP/1.1 201 Created
    Content-ID: 1
    Content-Type: application/atom+xml;charset=utf-8
    Cache-Control: no-cache
    ETag: W/"datetime'2011-03-13T07%3A28%3A53.9995832Z'"
    Location: http://ACCOUNT.table.core.windows.net/Novel(PartitionKey='An%20Author',RowKey='Third%20Book')
    DataServiceVersion: 1.0;

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xml:base="http://ACCOUNT.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2011-03-13T07%3A28%3A53.9995832Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
      <id>http://ACCOUNT.table.core.windows.net/Novel(PartitionKey='An%20Author',RowKey='Third%20Book')</id>
      <title type="text"></title>
      <updated>2011-03-13T07:28:54Z</updated>
      <author>
        <name />
      </author>
      <link rel="edit" title="Novel" href="Novel(PartitionKey='An%20Author',RowKey='Third%20Book')" />
      <category term="ACCOUNT.Novel" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
      <content type="application/xml">
        <m:properties>
          <d:PartitionKey>An Author</d:PartitionKey>
          <d:RowKey>Third Book</d:RowKey>
          <d:Timestamp m:type="Edm.DateTime">2011-03-13T07:28:53.9995832Z</d:Timestamp>
          <d:Artist>An Author</d:Artist>
          <d:Title>Third Book</d:Title>
        </m:properties>
      </content>
    </entry>
    --changesetresponse_3f3997db-60a3-4a0f-99a1-5dbe5e1253c3
    Content-Type: application/http
    Content-Transfer-Encoding: binary

    HTTP/1.1 201 Created
    Content-ID: 2
    Content-Type: application/atom+xml;charset=utf-8
    Cache-Control: no-cache
    ETag: W/"datetime'2011-03-13T07%3A28%3A54.0005832Z'"
    Location: http://ACCOUNT.table.core.windows.net/Novel(PartitionKey='An%20Author',RowKey='Fourth%20Book')
    DataServiceVersion: 1.0;

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xml:base="http://ACCOUNT.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2011-03-13T07%3A28%3A54.0005832Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
      <id>http://ACCOUNT.table.core.windows.net/Novel(PartitionKey='An%20Author',RowKey='Fourth%20Book')</id>
      <title type="text"></title>
      <updated>2011-03-13T07:28:54Z</updated>
      <author>
        <name />
      </author>
      <link rel="edit" title="Novel" href="Novel(PartitionKey='An%20Author',RowKey='Fourth%20Book')" />
      <category term="ACCOUNT.Novel" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
      <content type="application/xml">
        <m:properties>
          <d:PartitionKey>An Author</d:PartitionKey>
          <d:RowKey>Fourth Book</d:RowKey>
          <d:Timestamp m:type="Edm.DateTime">2011-03-13T07:28:54.0005832Z</d:Timestamp>
          <d:Artist>An Author</d:Artist>
          <d:Title>Fourth Book</d:Title>
        </m:properties>
      </content>
    </entry>
    --changesetresponse_3f3997db-60a3-4a0f-99a1-5dbe5e1253c3--
    --batchresponse_7c5c9678-0b18-4363-93f9-a55d9e30c2b8--

    • Marked as answer by KevinGZ Sunday, March 13, 2011 7:55 AM
    • Unmarked as answer by KevinGZ Wednesday, May 4, 2011 4:35 AM
    • Proposed as answer by Joe Giardino Tuesday, July 19, 2011 4:47 PM
    Sunday, March 13, 2011 7:42 AM
    Answerer
  • CreateAuthorizationHeader(stringToSign); 
    This function has not been resolved. Can you add code for this function, Thanks
    Wednesday, May 4, 2011 4:36 AM
  • private String CreateAuthorizationHeader(String canonicalizedString)
    {
    	String signature = string.Empty;
    	using (HMACSHA256 hmacSha256 = new HMACSHA256(AzureStorageConstants.Key))
    	{
    		Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
    		signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
    	}
    
    	String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", AzureStorageConstants.SharedKeyAuthorizationScheme, AzureStorageConstants.Account, signature);
    
    	return authorizationHeader;
    }
    
    
    • Marked as answer by Brad Calder Monday, March 12, 2012 9:20 AM
    Wednesday, May 4, 2011 4:54 AM
    Answerer