Azure Tables: Create/Delete example
ok, after some on-and-off poking around w/ Azure Storage, i finally got to the point where i can create and delete tables! along the way, i uncovered a minor bug (an omission, really) in the MSDN documentation for Create Table. turns out the <updated /> element cannot be null (as indicated on the docs). of course, i compounded my problem by first using the *wrong* string format for the date-time. but once i got a hint from the forum-meisters, i was all set.
the full story is in this thread on the MSDN Azure forums.
below is a complete stand-alone console app that handles creating a table in your Azure Storage space. you'll need to supply your project name, sharedkey, and the new table name for this to work.
using System;
using System.Text;
using System.Web;
using System.Net;
using System.IO;
using System.Security.Cryptography;
namespace CreateTable
{
class Program
{
static void Main(string[] args)
{
// supply for your account
string account = "*** yourProjectName";
string sharedKey = "*** yourSharedKey";
string tableName = "*** yourNewTableName";
// supply for your account
string endPoint = string.Format("http://{0}.table.core.windows.net", account);
string contentType = "application/atom+xml";
string keyType = "SharedKey";
string contentMD5 = string.Empty;
string fmtHeader = "{0} {1}:{2}";
string fmtStringToSign = "{0}\n{1}\n{2}\n{3:R}\n{4}";
string authValue = string.Empty;
string sigValue = string.Empty;
string authHeader = string.Empty;
string method = string.Empty;
string rtnBody = string.Empty;
string reqBody = string.Empty;
string canonicalResource = string.Format("/{0}/{1}", account, "Tables");
string requestUrl = string.Format("{0}/{1}", endPoint, "Tables");
DateTime requestDate = DateTime.UtcNow;
method = "POST";
reqBody = string.Format(createTableXml, requestDate, tableName);
contentMD5 = MD5(reqBody);
authValue = string.Format(fmtStringToSign, method, contentMD5, contentType, requestDate, canonicalResource);
sigValue = MacSha(authValue, Convert.FromBase64String(sharedKey));
authHeader = string.Format(fmtHeader, keyType, account, sigValue);
try
{
WebRequest req = WebRequest.Create(requestUrl);
req.Headers.Add("content-md5", contentMD5);
req.Headers.Add("x-ms-date", string.Format("{0:R}", requestDate));
req.Headers.Add("authorization", authHeader);
req.ContentType = contentType;
req.ContentLength = reqBody.Length;
req.Method = method;
using (StreamWriter sw = new StreamWriter(req.GetRequestStream()))
{
sw.Write(reqBody);
sw.Close();
}
WebResponse resp = req.GetResponse();
using (StreamReader sr = new StreamReader(resp.GetResponseStream(), true))
{
rtnBody = sr.ReadToEnd();
sr.Close();
}
Console.WriteLine(rtnBody);
}
catch (WebException wex)
{
if (wex.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse wrsp = (HttpWebResponse)wex.Response;
Console.WriteLine(string.Format("ERROR: {0} : {1}",wrsp.StatusCode,wrsp.StatusDescription));
}
else
{
Console.WriteLine(string.Format("ERROR: {0}",wex.Message));
}
}
}
// hashing helper
static string MacSha(string canonicalizedString, byte[] key)
{
byte[] dataToMAC = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
using (HMACSHA256 hmacsha1 = new HMACSHA256(key))
{
return System.Convert.ToBase64String(hmacsha1.ComputeHash(dataToMAC));
}
}
static string MD5(string data)
{
return MD5(data, false);
}
static string MD5(string data, bool removeTail)
{
string rtn = Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.Default.GetBytes(data)));
if (removeTail)
return rtn.Replace("=", "");
else
return rtn;
}
static string createTableXml = @"<?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>{0:yyyy-MM-ddTHH:mm:ss.fffffffZ}</updated>
<author>
<name />
</author>
<id />
<content type=""application/xml"">
<m:properties>
<d:TableName>{1}</d:TableName>
</m:properties>
</content>
</entry>";
}
}