I am trying to put a blob with Azure rest api. i made a “GET” request successfully but i had issues with “PUT” request. When i try to make “PUT” request i get a 404error (i have seen same post in stackoverflow but it didnt help me).i am not sure if the MessageSignature that i use is correct(i have tried MessageSignaturePut but didnt work). Any suggestions?
public void UploadBlobWithRestAPI(string uri, DateTime now) { string blobName = "test.txt"; string method = "PUT"; string sampleContent = "This is sample text."; int contentLength = Encoding.UTF8.GetByteCount(sampleContent); string queryString = (new Uri(uri)).Query; string blobContainerUri = uri.Substring(0, uri.Length - queryString.Length); string requestUri = string.Format(CultureInfo.InvariantCulture, "{0}/{1}{2}", blobContainerUri, blobName, queryString); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri); string nnow = now.ToString("R", System.Globalization.CultureInfo.InvariantCulture); request.Method = method; request.Headers.Add("x-ms-version", "2015-02-21"); request.Headers.Add("x-ms-date", nnow); request.ContentType = "text/plain; charset=UTF-8"; request.Headers.Add("x-ms-blob-type", "BlockBlob"); request.ContentLength = contentLength; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength); } request.Headers.Add("Authorization", AuthorizationHeader(method, now, request, "", "")); using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse()) { MessageBox.Show(resp.StatusCode.ToString()); } } public string AuthorizationHeader(string method, DateTime now, HttpWebRequest request, string ifMatch = "", string md5 = "") { string MessageSignature; string StorageKey = "xxx"; string StorageAccount = "upgradedevstorage"; MessageSignature = String.Format("{0}nnn{1}n{5}nnnn{2}nnnn{3}{4}", method, (method == "GET" || method == "HEAD") ? String.Empty : request.ContentLength.ToString(), ifMatch, GetCanonicalizedHeaders(request), GetCanonicalizedResource(request.RequestUri, StorageAccount), md5 ); ??? //string MessageSignaturePut= String.Format("{0}nn{1}nn{2}{3}", // method, // "text/plain; charset=UTF-8", // GetCanonicalizedHeaders(request), // GetCanonicalizedResource(request.RequestUri, StorageAccount) // ); byte[] SignatureBytes = System.Text.Encoding.UTF8.GetBytes(MessageSignature); System.Security.Cryptography.HMACSHA256 SHA256 = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(StorageKey)); string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes)); string AuthorizationHeader = "SharedKey " + StorageAccount + ":" + Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes)); return AuthorizationHeader; }
Answer
Please consider the following code snippet. This should work for you.
void UploadBlobWithRestAPI() { string storageKey = "<your access key here>"; string storageAccount = "<your storage account name here>"; string containerName = "<your container name here>"; string blobName = "test.txt"; string method = "PUT"; string sampleContent = "This is sample text."; int contentLength = Encoding.UTF8.GetByteCount(sampleContent); string requestUri = $"https://{storageAccount}.blob.core.windows.net/{containerName}/{blobName}"; 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", "2015-12-11"); request.Headers.Add("x-ms-date", now); request.Headers.Add("x-ms-blob-type", "BlockBlob"); request.Headers.Add("Authorization", AuthorizationHeader(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()) { MessageBox.Show(resp.StatusCode.ToString()); } } public string AuthorizationHeader(string method, string now, HttpWebRequest request, string storageAccount, string storageKey, string containerName, string blobName) { string headerResource = $"x-ms-blob-type:BlockBlobnx-ms-date:{now}nx-ms-version:2015-12-11"; string urlResource = $"/{storageAccount}/{containerName}/{blobName}"; string stringToSign = $"{method}nnn{request.ContentLength}nn{request.ContentType}nnnnnnn{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; }
And the traffic captured by Fiddler as follows: