2
votes

I am trying to communicate with my Container on Azure Blob Storage through a console application. I cannot use the SDK hence REST is my only option. Language is C# with .NET 4.5.2.

I have tried these two codes and both return the same error

Azure rest API put blob On StackOverflow

Azure Blob Storage Part 5(Non-StackOverflow)

The error that I receive is 400 Bad Request Error from my console application

Has anybody else faced the same issue and successfully resolved it?

I have added a CORS rule with (*) for almost everything

The code is an exact duplicate of the two links hence I am not adding it here.

    class Program
   {
    static void Main(string[] args)
    {

        UploadBlobWithRestAPI();
    }

    public static void UploadBlobWithRestAPI()
    {

        string storageKey = "ffFJwPXTqyYvRoubNQEti/aQUUMwn41BG3KDtl/yGpG4DR1eKaHRq6Bhbw==";
        string storageAccount = "xyz";
        string containerName = "notes";
        string blobName = "test567";

        string method = "PUT";
        string sampleContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla id euismod urna. Maecenas scelerisque dolor purus, sed ullamcorper ipsum lobortis non. Nulla est justo, sodales at venenatis a, faucibus";
        int contentLength = Encoding.UTF8.GetByteCount(sampleContent);

        string requestUri = $"https://xyz.blob.core.windows.net/notes/test567";

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

        string now = DateTime.UtcNow.ToString("R");

        request.Method = method;
        request.ContentType = "text/plain; charset=UTF-8";
        request.ContentLength = contentLength;

        request.Headers.Add("x-ms-version", "2018-01-11");
        request.Headers.Add("x-ms-date", now);
        request.Headers.Add("x-ms-blob-type", "BlockBlob");
        request.Headers.Add("Authorization", AuthorizationHeader2(method, now, request, storageAccount, storageKey, containerName, blobName));

        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
        }

        using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
        {
            Console.WriteLine(resp.StatusCode.ToString());
            Console.ReadKey();
        }

    }

    public static string AuthorizationHeader2(string method, string now, HttpWebRequest request, string storageAccount, 
        string storageKey, string containerName, string blobName)
    {

        string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:"+ DateTime.UtcNow.ToString("R") +"\nx-ms-version:2018-01-11";
        string urlResource = "/xyz/notes/test567";
        string stringToSign =  method + "\n\n\n" + request.ContentLength + 
            "\n\n" + request.ContentType +"\n\n\n\n\n\n\n" + headerResource + "\n" + urlResource;


        HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(storageKey));
        string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));

        String AuthorizationHeader = String.Format("{0} {1}:{2}", "SharedKey", storageAccount, signature);
        return AuthorizationHeader;
    }


}
1
Read How to Ask and show the relevant code. - CodeCaster
Can you please edit your question and include your code. - Gaurav Mantri
No, because it throws an exception before the response object can be initialized using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse()) - Sudeep
Please add request.Headers.Add("x-ms-blob-type", "BlockBlob"); and see if that solves the problem. You're missing this required header in your request. - Gaurav Mantri

1 Answers

5
votes

There are two issues with your code:

  1. You're using an invalid service version. Latest Storage Service REST API version is 2017-04-17 and not 2018-01-11. Once you change that, you will not get 400 error (but you will get 403 error).
  2. In your headerResource, you are generating a new date/time value which would be different than the date/time value in your x-ms-date header. Because of this you will get 403 error. So essentially your code would be:

        string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:" + now + "\nx-ms-version:2017-04-17";
    

I made these two fixes and after that I was able to upload the data.

Here's the complete code:

    public static void UploadBlobWithRestAPI()
    {

        string storageKey = "ffFJwPXTqyYvRoubNQEti/aQUUMwn41BG3KDtl/yGpG4DR1eKaHRq6Bhbw==";
        string storageAccount = "xyz";
        string containerName = "notes";
        string blobName = "test567";

        string method = "PUT";
        string sampleContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla id euismod urna. Maecenas scelerisque dolor purus, sed ullamcorper ipsum lobortis non. Nulla est justo, sodales at venenatis a, faucibus";
        int contentLength = Encoding.UTF8.GetByteCount(sampleContent);

        string requestUri = $"https://xyz.blob.core.windows.net/notes/test567";

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

        string now = DateTime.UtcNow.ToString("R");

        request.Method = method;
        request.ContentType = "text/plain; charset=UTF-8";
        request.ContentLength = contentLength;

        request.Headers.Add("x-ms-version", "2017-04-17");
        request.Headers.Add("x-ms-date", now);
        request.Headers.Add("x-ms-blob-type", "BlockBlob");
        request.Headers.Add("Authorization", AuthorizationHeader2(method, now, request, storageAccount, storageKey, containerName, blobName));

        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
        }

        using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
        {
            Console.WriteLine(resp.StatusCode.ToString());
            Console.ReadKey();
        }

    }

    public static string AuthorizationHeader2(string method, string now, HttpWebRequest request, string storageAccount,
        string storageKey, string containerName, string blobName)
    {

        string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:" + now + "\nx-ms-version:2017-04-17";
        string urlResource = "/xyz/notes/test567";
        string stringToSign = method + "\n\n\n" + request.ContentLength +
            "\n\n" + request.ContentType + "\n\n\n\n\n\n\n" + headerResource + "\n" + urlResource;


        HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(storageKey));
        string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));

        String AuthorizationHeader = String.Format("{0} {1}:{2}", "SharedKey", storageAccount, signature);
        return AuthorizationHeader;
    }