none
Possible bug: ContentMD5 not working in the Storage Client library?

    Question

  • To sum it up. The ContentMD5 is not populated when I use the ListBlobs method on a container. But if I use the REST API to list blobs in the same container, the returned XML contains the MD5 value. Also, when using the ListBlobs method on a container and having Fiddle running, I can see in Fiddle, that thee MD5 value is in the response.

    Thanks to Gaurav Mantri for trying with Fiddle and telling me about it!

    I have already made a blog post of this. Read the full detail including code to reproduce here: http://toolheaven.net/post/ContentMD5-not-working-in-the-Storage-Client-library.aspx

    Here is the code to reproduce:

    string account = "ACCOUNT NAME";
    string storageKey = "STORAGE KEY";
    string containerName = "md5test";
    
    /* ListBlobs done by storage library */
    StorageCredentialsAccountAndKey credentials =
     new StorageCredentialsAccountAndKey(
      account, 
      storageKey);
    CloudStorageAccount storageAccount = new CloudStorageAccount(credentials, false);
    CloudBlobClient client = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = client.GetContainerReference(containerName);
    container.CreateIfNotExist();
    
    string blobContent = "This is a test";
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(blobContent));
    CloudBlob cloudBlob = container.GetBlobReference("MyBlob.txt");
    cloudBlob.Properties.ContentMD5 = Convert.ToBase64String(hashBytes);
    cloudBlob.UploadText(blobContent);
    
    foreach (var blob in container.ListBlobs().OfType())
    {
     Console.WriteLine(blob.Uri.LocalPath + " MD5 = " +
      blob.Properties.ContentMD5 ?? "Not populated");
    }
    
    /* ListBlobs done by REST */
    DateTime now = DateTime.UtcNow;
    
    string nowString = now.ToString("R", CultureInfo.InvariantCulture);
    
    string canonicalizedResource = 
     string.Format("/{0}/{1}\ncomp:list\nrestype:container", 
     account, containerName);
    string canonicalizedHeaders = 
     string.Format("x-ms-date:{0}\nx-ms-version:2009-09-19", 
     nowString);
    
    string messageSignature =
     string.Format("GET\n\n\n\n\n\n\n\n\n\n\n\n{0}\n{1}",
     canonicalizedHeaders,
     canonicalizedResource
    
    );
    
    byte[] SignatureBytes = Encoding.UTF8.GetBytes(messageSignature);
    HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(storageKey));
    String authorizationHeader = 
     string.Format("SharedKey {0}:{1}", 
     account, 
     Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes)));
    
    
    Uri url = new Uri(
     string.Format("http://{0}.blob.core.windows.net/{1}?restype=container&comp=list",
     account, containerName));
    HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
    request.Method = "GET";
    request.ContentLength = 0;
    request.Headers.Add("x-ms-date", nowString);
    request.Headers.Add("x-ms-version", "2009-09-19");
    request.Headers.Add("Authorization", authorizationHeader);
    
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Stream responseStream = response.GetResponseStream();
    StreamReader reader = new StreamReader(responseStream);
    
    string responseString = reader.ReadToEnd();
    
    reader.Close();
    responseStream.Close();
    response.Close();
    
    XElement responseElement = XElement.Parse(responseString);
    
    foreach (XElement element in responseElement.Descendants("Content-MD5"))
    {
     string name = element.Parent.Parent.Element("Name").Value;
     string md5value = element.Value;
    
     if (string.IsNullOrEmpty(md5value))
     {
      md5value = "Not populated";
     }
    
     Console.WriteLine(name + " MD5 = " + md5value);
    }
    

    and here is the output of running that code:

    /md5test/MyBlob.txt MD5 =
    MyBlob.txt MD5 = zhFORQHS9OLc6j4XtUbzOQ==

     

     


    Friday, July 01, 2011 10:39 PM

Answers

All replies