none
getting 403 forbidden webexception : azure blob put request.

    Question

  • I am using this code to upload some text directly to azure blob using rest api. I am getting an webexception 403 forbidden. Can someone please tell me where am i going wrong in my code.

     

      private void PutBlob(String containerName, String blobName , CloudBlob blob)

      {

        String requestMethod = "PUT";



        String urlPath = String.Format("{0}", blobName);



        String storageServiceVersion = "2009-10-01";



        String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);



        // if (uploadPST.HasFile)

       // {

          string content = "Sample file";

          // Stream content = uploadPST.FileBytes;

          UTF8Encoding utf8Encoding = new UTF8Encoding();

          Byte[] blobContent = utf8Encoding.GetBytes(content);

          Int32 blobLength = blobContent.Length;





          const String blobType = "BlockBlob";



         /* String canonicalizedHeaders = String.Format(

             "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",

             blobType,

             dateInRfc1123Format,

             storageServiceVersion);*/



          String canonicalizedHeaders = String.Format(

             "x-ms-date:{0}\nx-ms-meta-m1:{1}\nx-ms-meta-m1:{2}",

              dateInRfc1123Format,

             "v1",

             "v2");



          String canonicalizedResource = String.Format("/{0}/{1}", myaccount, urlPath);



          String stringToSign = String.Format(

             "{0}\n\n{1}\n\n{2}\n{3}",

             requestMethod,

             "text/plain; charset=UTF-8",

             canonicalizedHeaders,

             canonicalizedResource);







          String authorizationHeader = CreateAuthorizationHeader(stringToSign, blob);



          Uri uri = new Uri(CloudStorageAccount.FromConfigurationSetting("DataConnectionString").BlobEndpoint + "/" + urlPath);

          HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

          request.Method = requestMethod;





          // request.Headers.Add("x-ms-blob-type", blobType);

          request.Headers.Add("x-ms-date", dateInRfc1123Format);

         // request.Headers.Add("x-ms-version", storageServiceVersion);

          request.Headers.Add("Authorization", authorizationHeader);

          request.ContentLength = blobLength;



          using (Stream requestStream = request.GetRequestStream())

          {

            requestStream.Write(blobContent ,0 ,blobLength);

          }



          using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())

          {

            String ETag = response.Headers["ETag"];

          }

       // }

      }



    Rau
    • Edited by elipsis.rau Thursday, January 06, 2011 9:03 AM
    Thursday, January 06, 2011 7:50 AM

Answers

  • Hi Rau,

    Finally!!! I should have seen this earlier but there is an issue with your CreateAuthorizationHeader() function especially with the following line:

    byte[] storageKey = utf8Encoding.GetBytes(key);

    It should be:

    byte[] storageKey = Convert.FromBase64String(key);

    Once you make this change, the 403 error should go away but you'll have to ensure that the blob container in question exists otherwise you'll get a 404 error.

    Hope this helps.

    Thanks

    Gaurav

    Thursday, January 06, 2011 1:32 PM

All replies

  • I am using this code to upload some text directly to azure blob using rest api. I am getting an webexception 403 forbidden. Can someone please tell me where am i going wrong in my code.

     

      private void PutBlob(String containerName, String blobName , CloudBlob blob)
    {
    String requestMethod = "PUT";

    String urlPath = String.Format("{0}", blobName);

    String storageServiceVersion = "2009-10-01";

    String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);

    // if (uploadPST.HasFile)
    // {
    string content = "Sample file";
    // Stream content = uploadPST.FileBytes;
    UTF8Encoding utf8Encoding = new UTF8Encoding();
    Byte[] blobContent = utf8Encoding.GetBytes(content);
    Int32 blobLength = blobContent.Length;


    const String blobType = "BlockBlob";

    /* String canonicalizedHeaders = String.Format(
    "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
    blobType,
    dateInRfc1123Format,
    storageServiceVersion);*/

    String canonicalizedHeaders = String.Format(
    "x-ms-date:{0}\nx-ms-meta-m1:{1}\nx-ms-meta-m1:{2}",
    dateInRfc1123Format,
    "v1",
    "v2");

    String canonicalizedResource = String.Format("/{0}/{1}", myaccount, urlPath);

    String stringToSign = String.Format(
    "{0}\n\n{1}\n\n{2}\n{3}",
    requestMethod,
    "text/plain; charset=UTF-8",
    canonicalizedHeaders,
    canonicalizedResource);



    String authorizationHeader = CreateAuthorizationHeader(stringToSign, blob);

    Uri uri = new Uri(CloudStorageAccount.FromConfigurationSetting("DataConnectionString").BlobEndpoint + "/" + urlPath);
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.Method = requestMethod;


    // request.Headers.Add("x-ms-blob-type", blobType);
    request.Headers.Add("x-ms-date", dateInRfc1123Format);
    // request.Headers.Add("x-ms-version", storageServiceVersion);
    request.Headers.Add("Authorization", authorizationHeader);
    request.ContentLength = blobLength;

    using (Stream requestStream = request.GetRequestStream())
    {
    requestStream.Write(blobContent ,0 ,blobLength);
    }

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
    String ETag = response.Headers["ETag"];
    }
    // }
    }
    • Merged by Steve Marx Thursday, January 06, 2011 9:35 AM appears to be duplicate
    Thursday, January 06, 2011 7:39 AM
  • I have a post showing an example of the Put Blob operation in the Azure Storage Services REST API. The first thing I would correct here is the storage service version which appears to be an invalid value. The latest version is 2009-09-19. The value quoted here, 2009-10-01, is the version for the Azure Service Management API not the Storage Services REST API.
    Thursday, January 06, 2011 8:55 AM
  • Thanks for the reply. I have another question. Do we need to pass the certificate also?
    Rau
    Thursday, January 06, 2011 9:05 AM
  • Hi,

    There are a few things that I noticed in your code above which could cause this 403 error (based on http://msdn.microsoft.com/en-us/library/dd179451.aspx):

    1. You're not passing "x-ms-version" request header.

    2. You're not passing "x-ms-blob-type" request header.

    3. Even though you're using metadata headers in creating "canonicalizedHeaders" however these headers are missing from your request header collection. Also I noticed that you're passing same metadata header "x-ms-meta-m1" when creating ""canonicalizedHeaders".

    You may also find this blog post from Neil helpful: http://convective.wordpress.com/2010/08/18/examples-of-the-windows-azure-storage-services-rest-api/

    Hope this helps.

    Thanks

    Gaurav Mantri

    Cerebrata Software

    http://www.cerebrata.com

     

    Thursday, January 06, 2011 9:08 AM
  • Now I have followed the steps as in given in the post . This is my code. I am still getting the same exception "Remote server returned an error : 403 frobidden".

    What does AzureStorageConstants.SharedKeyAuthorizationScheme mean exactly? As per my understanding it can be sharedKey or sharedKetLite . Is That correct?

     

     private String CreateAuthorizationHeader(String canonicalizedString, CloudBlob blob)
            {
                String signature = string.Empty;

              
               
                using (HMACSHA256 hmacSha256 = new HMACSHA256())
                {
                    Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
                    signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
                }

               

                String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKeyLite", myAccountNAme, signature);

                return authorizationHeader;
           }

            private void PutBlob(String containerName, String blobName , CloudBlob blob)
            {
                String requestMethod = "PUT";

                String urlPath = String.Format("{0}",  blobName);

                String storageServiceVersion = "2009-09-19";

                String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);

            
                    string content = "Sample file";
                    // Stream content = uploadPST.FileBytes;
                    UTF8Encoding utf8Encoding = new UTF8Encoding();
                    Byte[] blobContent = utf8Encoding.GetBytes(content);
                    Int32 blobLength = blobContent.Length;


                    const String blobType = "BlockBlob";

                    String canonicalizedHeaders = String.Format(
                          "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
                          blobType,
                          dateInRfc1123Format,
                          storageServiceVersion);

               
                    String canonicalizedResource = String.Format("/{0}/{1}", myAccountName, urlPath);

                 

                    String stringToSign = String.Format(
                  "{0}\n\n\n{1}\n\n\n\n\n\n\n\n\n{2}\n{3}",
                  requestMethod,
                  blobLength,
                  canonicalizedHeaders,
                  canonicalizedResource);



                    String authorizationHeader = CreateAuthorizationHeader(stringToSign, blob);

                    Uri uri = new Uri(

    CloudStorageAccount.FromConfigurationSetting("DataConnectionString").BlobEndpoint
    

    + "/" + urlPath);
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                    request.Method = requestMethod;
                  
                
                    request.Headers.Add("x-ms-blob-type", blobType);
                    request.Headers.Add("x-ms-date", dateInRfc1123Format);
                  
                    request.Headers.Add("x-ms-version", storageServiceVersion);
                    request.Headers.Add("Authorization", authorizationHeader);
                    request.ContentLength = blobLength;

                    using (Stream requestStream = request.GetRequestStream())
                    {
                        requestStream.Write(blobContent ,0 ,blobLength);
                    }

                    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                    {
                        String ETag = response.Headers["ETag"];
                    }
            
            }


    Rau
    Thursday, January 06, 2011 9:30 AM
  • Hi,

    Are you trying to upload data in development storage or cloud storage? Please take a look at this link (http://msdn.microsoft.com/en-us/library/dd179428.aspx) to understand about SharedKey and SharedKeyLite authentication schemes. It seems that you're using the format defined for "SharedKey":

    String stringToSign = String.Format(
           "{0}\n\n\n{1}\n\n\n\n\n\n\n\n\n{2}\n{3}",
           requestMethod,
           blobLength,
           canonicalizedHeaders,
           canonicalizedResource);
    
    

    However you are specifying "SharedKeyLite" to sign:

    String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKeyLite", myAccountNAme, signature);
    
    

    Hope this helps.

    Thanks

    Gaurav

    Thursday, January 06, 2011 10:10 AM
  • Ya. Thanks. I realized that i had used a wrong authentication scheme. I changed it to sharedKey. But I am still getting the exception. And I am uploading data to cloud storage.

    Rau
    Thursday, January 06, 2011 10:27 AM
  • Hi,

    I noticed one more thing. Does your blobName variable includes blob container name as well? Reason I am asking this is because when you are creating "canonicalizedResource", you're only passing account name and urlPath (which is set to the name of the blob).

    String canonicalizedResource = String.Format("/{0}/{1}", myAccountName, urlPath);

    It should have been:

    String urlPath = String.Format(“{0}/{1}”, containerName, blobName);

    String canonicalizedResource = String.Format("/{0}/{1}", myAccountName, urlPath);

    Hope this helps.

    Thanks

    Gaurav

    Thursday, January 06, 2011 10:59 AM
  • Ya. The blobname  contains the container name as well. Thats the reason i have not used the containername.

     


    Rau
    Thursday, January 06, 2011 11:06 AM
  • Hi,

    Everything else looks OK. Did you check the error details for this 403 error. You can use the code below to see more details about this 403 error. Put this code in the catch block:

    WebException webEx = exception as WebException;
    if (webEx != null)
    {
    	WebResponse resp = webEx.Response;
    	if (resp != null)
    	{
    		using (StreamReader sr = new StreamReader(resp.GetResponseStream(), true))
    		{
    			string responseText = sr.ReadToEnd();//This is where details about this 403 message can be found
    		}
    	}
    }

    Please share the contents of responseText here.

    Hope this helps.

    Thanks

    Gaurav

    Thursday, January 06, 2011 11:30 AM
  • This is the response that i have got .

     

    <?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
    RequestId:64d7af60-2d91-4d92-b801-a973138d8d82
    Time:2011-01-06T11:52:21.8216796Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'n6TD+n6j865aRom+U/sk5KKKvt6N+k0wNXdBsqac0eA=' is not the same as any computed signature. Server used following string to sign: 'PUT


    11








    x-ms-blob-type:BlockBlob
    x-ms-date:Thu, 06 Jan 2011 11:51:47 GMT
    x-ms-version:2009-09-19
    /myAccount/tempstorage/pst/ZDGGP634299114975250520/temp.txt'.</AuthenticationErrorDetail></Error>

     

    Thank you.


    Rau
    Thursday, January 06, 2011 11:54 AM
  • Thanks a lot for your help Gaurav.

    I am sharing the link to my project. You will have to insert your account details to run it.

    I have not deployed the project. I am running the project locally.

    http://demos.dreamwarestech.com/azure/RestUpload.zip

     

    Thank you.


    Rau
    Thursday, January 06, 2011 12:18 PM
  • Hi Rau,

    Thanks for sharing the project. Let me try it out and get back to you.

    Regards

    Gaurav

    Thursday, January 06, 2011 12:34 PM
  • Hi Rau,

    Finally!!! I should have seen this earlier but there is an issue with your CreateAuthorizationHeader() function especially with the following line:

    byte[] storageKey = utf8Encoding.GetBytes(key);

    It should be:

    byte[] storageKey = Convert.FromBase64String(key);

    Once you make this change, the 403 error should go away but you'll have to ensure that the blob container in question exists otherwise you'll get a 404 error.

    Hope this helps.

    Thanks

    Gaurav

    Thursday, January 06, 2011 1:32 PM
  • Thanks a lot Gaurav. The code is working fine now.
    Rau
    Thursday, January 06, 2011 2:28 PM
  • Thanks a lot Gaurav. I have one more question . Can i upload large files using this approach. I tried uploading 23MB file and i got request timeout error.

    Rau
    Friday, January 07, 2011 5:33 AM
  • Hi Rau,

    You're welcome. I don't think you can upload a 23 MB file using this approach as the maximum sized blob which can be uploaded without breaking it into blocks is 4 MB. Anything over that would need to be split into blocks. You may want to read about Put Block (http://msdn.microsoft.com/en-us/library/dd135726.aspx) and Commit Block List (http://msdn.microsoft.com/en-us/library/dd179467.aspx) operations. I do have a question for you: Is there any particular reason why you want to go this route i.e. implementing REST API on your own instead of using Storage Client library provided by Microsoft (http://msdn.microsoft.com/en-us/library/wl_svchosting_mref_reference_home.aspx)? I'm just curious.

    Thanks

    Gaurav

    Friday, January 07, 2011 5:46 AM
  • Hi Gaurav,

    Thanks for your reply, i read about 'Put Block' and 'Put Block List' operations of REST API, and i decided that insted of using Blok Blob if i use PageBlob i dont need to split the file in to small chunks, now i am modifying my program to use PageBlob.(Give me a comment if i am wrong with this approch).

    And thanks for your curiousity also, if you really want to know more about that, please have a look to following link;

    http://social.msdn.microsoft.com/Forums/en-US/windowsazuremanagement/thread/6a8c1072-975d-4af9-845b-0fd743ee470d

    Basically in my application i want to upload a large file to webrole, need to process that file on webserver, and after processing that file, i want to upload it to BlobStorage.

    Actually i am using StorageClient library to upload that processed file to blob and its working fine but it is part of webrole means i am uploading that file from webserver to BlobStorage, and problem is I need to upload that Big file first to webserver and then process it.

    All problems now starts here. That's why i am using REST API to Upload a file directly to blob. Please reply if i am going wrong with this approch, or i need to change my approch. Any way please reply and have look on the link that i have provided.

    Thanks

     


    Rau
    Friday, January 07, 2011 7:23 AM
  • Hi Rau,

    There are few things to consider:

    1. Page blob v/s Block blob: The criteria for choosing between a page blob and a block blob should be solely based on how you want to use the blob. Block blobs are suitable for streaming purposes (e.g. images, documents, videos etc.) where you need to send the blob back to a client in some shape or form. Page blobs on the other hand are suitable when there are random read/writes involved. For example, you could upload a VHD as page blob mount it as an azure drive and start reading/writing into that. I'm not sure I am able to understand the usage of this blob from your description above.

    2. Network speed: Even though page blobs do not have a restriction of block size, still you would need to consider the network speed between your application and Azure data center. For example, I am here in India and the network connectivity is comparatively poorer as compared to say US. For me, if I try to upload even a 1 MB blob without splitting it, I will certainly get a timeout error. Thus it is much advisable to split a blob into blocks (in case of blob blocks) and into pages (in case of page blobs) and upload these chunks. The difference would come when you are uploading pages, they get committed immediately while for blocks to commit you would need to call "Commit Block List".

    3. Also I have seen your project (from the source code link). Essentially you're not directly uploading the blob into blob storage because first you will be using some kind of file uploader control (either ASP.Net or SWFUploader) and both of them would upload the file on web server first and then your server side code will execute which will push this data into blob storage. It would be direct if you had a separate utility (like our Cloud Storage Studio product which talks to blob storage directly) which is doing the upload. Then you would have some code in your web role which would read this blob and process it.

    I think what would work best in your case is if you are able to break this large blob into smaller chunks on the client side and start uploading these chunks to your webrole. As these chunks become available to your webrole you can either:

    Wait for all the chunks to arrive, reassemble that blob and then upload that blob in blob storage.

    OR

    Start moving these chunks into blob storage. If you're uploading them as block blob then you would need to commit the block list.

    Hope this helps.

    Thanks

    Gaurav

    Friday, January 07, 2011 8:15 AM
  • Hi Gaurav,

       Thanks a lot for your advice. But I want my files to be directly uploaded to blob using swfuploader. So I have opted for page blob now. Now I am again getting 403 exception. As per the documentation this is a two step process. 1. To create a page blob without any content uploaded with put blob. 2. Add content with put page request.

     

         My first step is failing. I am noit able to create a page blob. It gives 403 exception. Can you help me with this?

     

       private String CreateAuthorizationHeader(String canonicalizedString)
            {
                String signature = string.Empty;

                string key = "storageKey";
                //   UTF8Encoding utf8Encoding = new UTF8Encoding();
                byte[] storageKey = Convert.FromBase64String(key);

                using (HMACSHA256 hmacSha256 = new HMACSHA256(storageKey))
                {
                    Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
                    signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
                }


                String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKey", "accountName", signature);

                return authorizationHeader;
            }

            private void PutBlob(String blobName)
            {
                String requestMethod = "PUT";

                String urlPath = String.Format("{0}", blobName);

                String storageServiceVersion = "2009-09-19";

                String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
              
                UTF8Encoding utf8Encoding = new UTF8Encoding();
                Byte[] blobContent = uploadPST.FileBytes;
                Int32 blobLength = blobContent.Length;


            
                const String blobType = "PageBlob";

                String canonicalizedHeaders = String.Format(
                      "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
                      blobType,
                      dateInRfc1123Format,
                      storageServiceVersion);



                String canonicalizedResource = String.Format("/{0}/{1}", "accountName", urlPath);


                String stringToSign = String.Format(
              "{0}\n\n\n{1}\n\n\n\n\n\n\n\n\n{2}\n{3}",
              requestMethod,
              blobLength,
              canonicalizedHeaders,
              canonicalizedResource);



                String authorizationHeader = CreateAuthorizationHeader(stringToSign);

                Uri uri = new Uri("myHost" + "/" + urlPath);
             
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

              
                request.Method = requestMethod;
             
                request.Headers.Add("x-ms-blob-type", blobType);
                request.Headers.Add("x-ms-date", dateInRfc1123Format);
                request.Headers.Add("x-ms-blob-content-length", blobLength.ToString());
              
                request.Headers.Add("x-ms-version", storageServiceVersion);
        
                request.Headers.Add("Authorization", authorizationHeader);
               
             
                request.ContentLength = 0;


            
                try
                {
                    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                    {
                        String ETag = response.Headers["ETag"];
                    }
                }
                catch (Exception exception)
                {
                  //  Response resp = exception.Response;
                 
                            string responseText = exception.Message ;//This is where details about this 403 message can be found
                 

                }


            }


    Rau
    Friday, January 07, 2011 11:43 AM
  • Hi Rau,

    Looking at your code above, you would need to include "x-ms-blob-content-length" when constructing "canonicalizedHeaders".

    Hope this helps.

    Thanks

    Gaurav

    Friday, January 07, 2011 1:22 PM
  • Thanks Gaurav. I added the header. But it still failed. Gave the same exception.

    Rau
    Friday, January 07, 2011 2:34 PM
  • May be it's time to upload the project one more time :)

    Gaurav

    Friday, January 07, 2011 2:39 PM
  •  

    http://demos.dreamwarestech.com/azure/RestUpload.zip

    I have uploded the project. Its the same one as before with some changes in headers.

     


    Rau
    Saturday, January 08, 2011 4:58 AM
  • Hi Rau,

    Based on the documentation (http://msdn.microsoft.com/en-us/library/dd179428.aspx), your canonicalizedHeader string should have the request headers starting with x-ms- sorted alphabetically. So the code below:

    String canonicalizedHeaders = String.Format(
             "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}\nx-ms-blob-content-length:{3}",
             blobType,
             dateInRfc1123Format,
             storageServiceVersion,
             blobLength.ToString());
    

    should be changed to something like:

    String canonicalizedHeaders = String.Format(
             "x-mx-blob-content-length:{3}\nx-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
             blobType,
             dateInRfc1123Format,
             storageServiceVersion,
             blobLength.ToString());
    

    Please try it out and hopefully that should solve your problem.

    Hope this helps.

    Thanks

    Gaurav

     

    Sunday, January 09, 2011 3:21 PM
  •  

    Hi Gaurav,

    I found a link http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/ce26dec6-d8a8-4036-a805-cb319e556a7d/ . This is the same approach as you had mnetioned in your earlier post. This approach is working for large files also. So I decided to go with it. But thanks for all the help. You gave me a lot of hints that has helped me understand blob storage better.


    Rau
    Monday, January 10, 2011 5:25 AM
  • Can someone help. Am facing same problem.. but using simple code to do things. Can someone help please. Am able to upload the same data using StorageClient dll. But with Http, am facing issues. On desktop it says (403) Forbidden Error.

    public bool StartGPSDataUpload(Guid raceId)
            {
                bool bResult = false;
                try
                {
                    string URL = "";
                    URL = "http://xxxx.blob.core.windows.net/videos/"+ Uri.EscapeDataString("6a3c2acd-8a2f-41ee-9203-137d7ba7ecd5-GPS-test.txt") +"?timeout=90";
                    WebReq = (HttpWebRequest)HttpWebRequest.Create(URL);
                    WebReq.Method = "PUT";
                    WebReq.KeepAlive = false;
                    WebReq.Headers["x-ms-version"] = "2011-08-18";
                    WebReq.UserAgent = "myapp";
                    WebReq.Headers["x-ms-blob-type"] = "BlockBlob";
                    WebReq.Headers["x-ms-date"] = DateTime.UtcNow.ToString("R");
                    WebReq.Headers["Authorization"] = "SharedKey xxxx:ioOqYh7CnftgX8c1DxX5OiRWL1v9TfIJMmTl8m4ogrY=";
                    gpsdataInByte = ReadGPSFile(raceId);
                    WebReq.ContentLength = gpsdataInByte.Length;
                    
                    using (HttpWebResponse response = (HttpWebResponse)WebReq.GetResponse())
                    {
                        String ETag = response.Headers["ETag"];
                        System.Windows.Forms.MessageBox.Show(ETag);
                    }
                    
                }
                catch (Exception ex)
                {
                    System.Windows.Forms.MessageBox.Show("error - " + ex.ToString());
                }
    
                return bResult;
            }

    Sunday, April 29, 2012 5:43 PM
  • I was able to get things working. Thanks for the details in this blob. A few things to note,

    1. In addition to the above, this article was helful http://convective.wordpress.com/2010/08/18/examples-of-the-windows-azure-storage-services-rest-api/
    2. In the above, without content length it worked

    String canonicalizedHeaders = String.Format(
             "x-mx-blob-content-length:{3}\nx-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
             blobType,
             dateInRfc1123Format,
             storageServiceVersion,
             blobLength.ToString());

    Here is the sample code for others. Usage will be (new AzureStorageHelper()).PutBlob("yourcontainername", "yourblobfilename");

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Security.Cryptography;
    using System.Globalization;
    using System.Net;
    using System.IO;
    
    namespace TestBlobUpload
    {
        class AzureStorageConstants
        {
            public static string Key="xxxx";
            public static string SharedKeyAuthorizationScheme = "SharedKey";
            public static string Account="xxxx";
            public static string BlobEndPoint="http://xxxxx.blob.core.windows.net/";
            
        }
        class AzureStorageHelper
        {
            public String CreateAuthorizationHeader(String canonicalizedString)
             {
                 String signature = string.Empty;
                 //UTF8Encoding utf8Encoding = new UTF8Encoding();
                 //byte[] storageKey = utf8Encoding.GetBytes(AzureStorageConstants.Key);
                 byte[] storageKey = Convert.FromBase64String(AzureStorageConstants.Key);
    
                 using (HMACSHA256 hmacSha256 = new HMACSHA256(storageKey))
                 {
                     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;
             }
    
            public void PutBlob(String containerName, String blobName)
             {
                 String requestMethod = "PUT";
     
                String urlPath = String.Format("{0}/{1}", containerName, blobName);
    
                String storageServiceVersion = "2011-08-18"; // "2009-09-19";
     
                String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
     
                String content = "The Name of This Band is Talking Heads";
                 UTF8Encoding utf8Encoding = new UTF8Encoding();
                 Byte[] blobContent = utf8Encoding.GetBytes(content);
                 Int32 blobLength = blobContent.Length;
     
                const String blobType = "BlockBlob";
     
                
                String canonicalizedHeaders = String.Format(
                       "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
                       blobType,
                       dateInRfc1123Format,
                       storageServiceVersion);
                /*
                String canonicalizedHeaders = String.Format(
                 "x-mx-blob-content-length:{3}\nx-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
                 blobType,
                 dateInRfc1123Format,
                 storageServiceVersion,
                 blobLength.ToString());
                */
                 String canonicalizedResource = String.Format("/{0}/{1}", AzureStorageConstants.Account, urlPath);
                 String stringToSign = String.Format(
                       "{0}\n\n\n{1}\n\n\n\n\n\n\n\n\n{2}\n{3}",
                       requestMethod,
                       blobLength,
                       canonicalizedHeaders,
                       canonicalizedResource);
                 String authorizationHeader = CreateAuthorizationHeader(stringToSign);
     
                Uri uri = new Uri(AzureStorageConstants.BlobEndPoint + urlPath);
                 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                 request.Method = requestMethod;
                 request.Headers.Add("x-ms-blob-type", blobType);
                 request.Headers.Add("x-ms-date", dateInRfc1123Format);
                 request.Headers.Add("x-ms-version", storageServiceVersion);
                 request.Headers.Add("Authorization", authorizationHeader);
                 request.ContentLength = blobLength;
    
                 try
                 {
                     using (Stream requestStream = request.GetRequestStream())
                     {
                         requestStream.Write(blobContent, 0, blobLength);
                     }
    
                     using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                     {
                         String ETag = response.Headers["ETag"];
                     }
                     System.Windows.Forms.MessageBox.Show("Success");
                 }
                 catch (WebException webEx)
                 {
                     if (webEx != null)
                     {
                         WebResponse resp = webEx.Response;
                         if (resp != null)
                         {
                             using (StreamReader sr = new StreamReader(resp.GetResponseStream(), true))
                             {
                                 string responseText = sr.ReadToEnd();//This is where details about this 403 message can be found
                                 System.Windows.Forms.MessageBox.Show("error - " + responseText);
                             }
                         }
                     }
                 }
             }
    
        }
    }
    

    Monday, April 30, 2012 2:50 PM