Put Stuff in Your Windows Azure Junk Trunk – Windows Azure Worker Role and Storage Queue

Click on Part 1 and Part 2 of this series to review the previous examples and code.  First and foremost have the existing code base created in the other two examples opened and ready in Visual Studio 2010.  Next, I’ll just start rolling ASAP.

In the JunkTrunk.Storage Project add the following class file and code to the project. This will get us going for anything else we needed to do for the application from the queue perspective.

public class Queue : JunkTrunkBase
{
    public static void Add(CloudQueueMessage msg)
    {
        Queue.AddMessage(msg);
    }

    public static CloudQueueMessage GetNextMessage()
    {
        return Queue.PeekMessage() != null ? Queue.GetMessage() : null;
    }

    public static List<CloudQueueMessage> GetAllMessages()
    {
        var count = Queue.RetrieveApproximateMessageCount();
        return Queue.GetMessages(count).ToList();
    }

    public static void DeleteMessage(CloudQueueMessage msg)
    {
        Queue.DeleteMessage(msg);
    }
}

Once that is done open up the FileBlobManager.cs file in the Models directory of the JunkTrunk ASP.NET MVC Web Application. In the PutFile() Method add this line of code toward the very end of that method. The method, with the added line of code should look like this.

public void PutFile(BlobModel blobModel)
{
    var blobFileName = string.Format("{0}-{1}", DateTime.Now.ToString("yyyyMMdd"), blobModel.ResourceLocation);
    var blobUri = Blob.PutBlob(blobModel.BlobFile, blobFileName);

    Table.Add(
        new BlobMeta
            {
                Date = DateTime.Now,
                ResourceUri = blobUri,
                RowKey = Guid.NewGuid().ToString()
            });

    Queue.Add(new CloudQueueMessage(blobUri + "$" + blobFileName));
}

Now that we have something adding to the queue, we want to process this queue message. Open up the JunkTrunk.WorkerRole and make sure you have the following references in the project.

Windows Azure References

Windows Azure References

Next create a new class file called PhotoProcessing.cs. First add a method to the class titled ThumbnailCallback with the following code.

public static bool ThumbnailCallback()
{
    return false;
}

Next add another method with a blobUri string and filename string as parameters. Then add the following code block to it.

private static void AddThumbnail(string blobUri, string fileName)
{
    try
    {
        var stream = Repository.Blob.GetBlob(blobUri);
 
        if (blobUri.EndsWith(".jpg"))
        {
            var image = Image.FromStream(stream);
            var myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
            var thumbnailImage = image.GetThumbnailImage(42, 32, myCallback, IntPtr.Zero);
            thumbnailImage.Save(stream, ImageFormat.Jpeg);
            Repository.Blob.PutBlob(stream, "thumbnail-" + fileName);
        }
        else
        {
            Repository.Blob.PutBlob(stream, fileName);
        }
    }
    catch (Exception ex)
    {
        Trace.WriteLine("Error", ex.ToString());
    }
}

Last method to add to the class is the Run() method.

public static void Run()
{
    var queueMessage = Repository.Queue.GetNextMessage();
 
    while (queueMessage != null)
    {
        var message = queueMessage.AsString.Split('$');
        if (message.Length == 2)
        {
            AddThumbnail(message[0], message[1]);
        }
 
        Repository.Queue.DeleteMessage(queueMessage);
        queueMessage = Repository.Queue.GetNextMessage();
    }
}

Now open up the WorkerRole.cs File and add the following code to the existing methods and add the additional even method below.

public override void Run()
{
    Trace.WriteLine("Junk Trunk Worker entry point called", "Information");

    while (true)
    {
        PhotoProcessing.Run();

        Thread.Sleep(60000);
        Trace.WriteLine("Working", "Junk Trunk Worker Role is active and running.");
    }
}

public override bool OnStart()
{
    ServicePointManager.DefaultConnectionLimit = 12;
    DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString");
    RoleEnvironment.Changing += RoleEnvironmentChanging;

    CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
    {
        configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
        RoleEnvironment.Changed += (sender, arg) =>
        {
            if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                .Any((change) => (change.ConfigurationSettingName == configName)))
            {
                if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                {
                    RoleEnvironment.RequestRecycle();
                }
            }
        };
    });

    Storage.JunkTrunkSetup.CreateContainersQueuesTables();

    return base.OnStart();
}

private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
{
    if (!e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)) return;
            
    Trace.WriteLine("Working", "Environment Change: " + e.Changes.ToList());
    e.Cancel = true;
}

At this point everything needed to kick off photo processing using Windows Azure Storage Queue as the tracking mechanism is ready. I’ll be following up these blog entries with some additional entries regarding rafactoring and streamlining what we have going on. I might even go all out and add some more functionality or some such craziness! So hope that was helpful and keep reading. I’ll have more bits of rambling and other trouble coming down the blob pipeline soon! Cheers!

Put Stuff in Your Windows Azure Junk Trunk – ASP.NET MVC Application

If you haven’t read Part 1 of this series (part 3 click here), you’ll need to in order to follow along with the JunkTrunk Repository.  Open the solution up if you haven’t already and navigate to the Models Folder within the ASP.NET MVC JunkTrunk Project.  In the folder add another class titled FileItemModel.cs and BlobModel.cs. Add the following properties to the FileItemModel.

public class FileItemModel
{
    public Guid ResourceId { get; set; }
    public string ResourceLocation { get; set; }
    public DateTime UploadedOn { get; set; }
}

Add the following property to the BlobModel and inherit from the FileItemModel Class.

public class BlobModel : FileItemModel
{
    public Stream BlobFile { get; set; }
}

Next add a new class file titled FileBlobManager.cs and add the following code to the class.

public class FileBlobManager
{
    public void PutFile(BlobModel blobModel)
    {
        var blobFileName = string.Format("{0}-{1}", DateTime.Now.ToString("yyyyMMdd"), blobModel.ResourceLocation);
        var blobUri = Blob.PutBlob(blobModel.BlobFile, blobFileName);

        Table.Add(
                new BlobMeta
                {
                    Date = DateTime.Now,
                    ResourceUri = blobUri,
                    RowKey = Guid.NewGuid().ToString()
                });
    }

    public BlobModel GetFile(Guid key)
    {
        var blobMetaData = Table.GetMetaData(key);
        var blobFileModel =
            new BlobModel
            {
                UploadedOn = blobMetaData.Date,
                BlobFile = Blob.GetBlob(blobMetaData.ResourceUri),
                ResourceLocation = blobMetaData.ResourceUri
            };
        return blobFileModel;
    }

    public List GetBlobFileList()
    {
        var blobList = Table.GetAll();

        return blobList.Select(
            metaData => new FileItemModel
            {
                ResourceId = Guid.Parse(metaData.RowKey),
                ResourceLocation = metaData.ResourceUri,
                UploadedOn = metaData.Date
            }).ToList();
    }

    public void Delete(string identifier)
    {
        Table.DeleteMetaDataAndBlob(Guid.Parse(identifier));
    }
}

Now that the repository, management, and models are all complete the focus can turn to the controller and the views of the application. At this point the break down of each data element within the data transfer object and the movement of the data back and forth becomes very important to the overall architecture. One of the things to remember is that the application should not pass back and forth data such as URIs or other long easy to hack strings. This is a good place to include Guids or if necessary integer values that identify the data that is getting created, updated, or deleted. This helps to simplify the UI and help decrease the chance of various injection attacks. The next step is to open up the HomeController and add code to complete each of the functional steps for the site.

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to the Windows Azure Blob Storing ASP.NET MVC Web Application!";
        var fileBlobManager = new FileBlobManager();
        var fileItemModels = fileBlobManager.GetBlobFileList();
        return View(fileItemModels);
    }

    public ActionResult About()
    {
        return View();
    }

    public ActionResult Upload()
    {
       return View();
    }

    public ActionResult UploadFile()
    {
        foreach (string inputTagName in Request.Files)
        {
            var file = Request.Files[inputTagName];

            if (file.ContentLength > 0)
            {
                var blobFileModel =
                    new BlobModel
                        {
                            BlobFile = file.InputStream,
                            UploadedOn = DateTime.Now,
                            ResourceLocation = Path.GetFileName(file.FileName)
                        };

                var fileBlobManager = new FileBlobManager();
                fileBlobManager.PutFile(blobFileModel);
            }
        }

        return RedirectToAction("Index", "Home");
    }

    public ActionResult Delete(string identifier)
    {
        var fileBlobManager = new FileBlobManager();
        fileBlobManager.Delete(identifier);
        return RedirectToAction("Index", "Home");
    }
}

The view hasn’t been created for the Upload just yet, so the method will cause a build error at this point. But before I add a view for this action, I’ll cover what has been created for the controller.

The Index Action I’ve changed moderately to have a list of the Blobs that are stored in the Windows Azure Blob Storage. This will be pulled from the manager class that we created earlier and passed into the view for rendering. I also, just for cosmetic reasons, changed the default display message passed into the ViewData so that the application would have something displayed more relevant to the application.

The About message I just left as is. The Upload action simply returns what will be a view we create.

The UploadFile Action checks for files within the request, builds up the model and then puts the model into storage via the manager.

The last method is the Delete Action that instantiates the manager and then calls a delete against the storage. This action then in turn traces back through, finds the Table & Blob Entities that are related to the specific blob and deletes both from the respective Windows Azure Storage Table and Blob Mediums.

The next step is to get the various views updated or added to enable the upload and deletion of the blob items.

Add a view titled Upload.aspx to the Home Folder of the Views within the JunkTrunk Project.

Upload View

Upload View

First change the inherits value for the view from System.Web.Mvc.ViewPage to System.Web.Mvc.ViewPage. After that add the following HTML to the view.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
	Upload an Image
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
	<h2>
		Upload</h2>
	<% using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, 
        new { enctype = "multipart/form-data" }))
	   {%>
	<%: Html.ValidationSummary(true) %>
	<fieldset>
		<legend>Fields</legend>
	  
		<div class="editor-label">
			Select file to upload to Windows Azure Blob Storage:
		</div>
		<div class="editor-field">
			<input type="file" id="fileUpload" name="fileUpload" />
		</div>
		<p>
			<input type="submit" value="Upload" />
		</p>
	</fieldset>
	<% } %>
	<div>
		<%: Html.ActionLink("Back to List", "Index") %>
	</div>
</asp:Content>

After adding the HTML, then change the HTML in the Index.aspx View to have an action link for navigating to the upload page and for viewing the list of uploaded Blobs. Change the inherits first form System.Web.Mvc.ViewPage to System.Web.Mvc.ViewPage<IEnumerable>. The rest of the changes are listed below.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        <%: ViewData["Message"] %></h2>
    <p>
        <%: Html.ActionLink("Upload", "Upload", "Home") %>
        a file to Windows Azure Blob Storage.
    </p>
    Existing Files:<br />
    <table>
        <tr>
            <th>
            </th>
            <th>
                FileName
            </th>
            <th>
                DownloadedOn
            </th>
        </tr>
        <% foreach (var item in Model)
           { %>
        <tr>
            <td>
                <%: Html.ActionLink("Delete", "Delete", 
                new { identifier = item.ResourceId })%>
            </td>
            <td>
                <%: item.ResourceLocation %>
            </td>
            <td>
                <%: String.Format("{0:g}", item.UploadedOn) %>
            </td>
        </tr>
        <% } %>
    </table>
</asp:Content>

Make sure the Windows Azure Project is set as the startup project and click on F5 to run the application. The following page should display first.

The Home Page o' Junk Trunk

The Home Page o' Junk Trunk

Click through on it to go to the upload page.

Selecting an Image to Put in The Junk Trunk

Selecting an Image to Put in The Junk Trunk

On the upload page select and image to upload and then click on upload. This will then upload the image and redirect appropriately to the home page.

The Image in the Junk Trunk

The Image in the Junk Trunk

On the home page the list should now have the uploaded blob image listed. Click delete to delete the image. When deleted the table and the blob itself will be removed from the Windows Azure Storage. To see that the data & image are being uploaded open up the Server Explorer within Visual Studio 2010.

Visual Studio 2010 Server Explorer

Visual Studio 2010 Server Explorer

View the data by opening up the Windows Azure Storage tree. Double click on either of the storage mediums to view table or blob data.

Windows Azure Storage

Windows Azure Storage

Put Stuff in Your Windows Azure Junk Trunk – Repository Base

Alright, so the title is rather stupid, but hey, it’s fun!  :)

This project I setup to provide some basic functionality with Windows Azure Storage.  I wanted to use each of the three mediums;  Table, Blob, and Queue, and this example will cover each of these things.  The application will upload and store images, provide a listing, some worker processing, and deletion of the images & associated metadata.  This entry is part 1 of this series, with the following schedule for subsequent entries:

Title aside, schedule laid out, description of the project completed, I’ll dive right in!

Putting Stuff in Your Junk Trunk

Create a new Windows Azure Project called PutJunkInIt.  (Click any screenshot for the full size, and also note some of the text may be off – I had to recreate a number of these images)

Windows Azure PutJunkInIt

Windows Azure PutJunkInIt

Next select the ASP.NET MVC 2 Web Application and also a Worker Role and name the projects JunkTrunk and JunkTrunk.WorkerRole.

Choosing Windows Azure Projects

Choosing Windows Azure Projects

In the next dialog choose to create the unit test project and click OK.

Create Unit Test Project

Create Unit Test Project

After the project is created the following projects are setup within the PutJunkInIt Solution.  There should be a JunkTrunk, JunkTrunk.Worker, JunkTrunk Windows Azure Deployment Project, and a JunkTrunk.Tests Project.

Solution Explorer

Solution Explorer

Next add a Windows Class Library Project and title it JunkTrunk.Storage.

Windows Class Library

Windows Class Library

Add a reference to the Microsoft.WindowsAzure.ServiceRuntime and Microsoft.WindowsAzure.StorageClient assemblies to the JunkTrunk.Storage Project.  Rename the Class1.cs file and class to JunkTrunkBase.  Now open up the Class1.cs file in the JunkTrunk.Storage Project.  First add the following fields and constructor to the class.

public const string QueueName = "metadataqueue";
public const string BlobContainerName = "photos";
public const string TableName = "MetaData";
static JunkTrunkBase()
{
    CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
    {
        configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
        RoleEnvironment.Changed
            += (sender, arg) =>
                    {
                        if (!arg.Changes.OfType()
                                .Any(change => (change.ConfigurationSettingName == configName)))
                            return;
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            RoleEnvironment.RequestRecycle();
                        }
                    };
    });
}

After that add the following blob container and reference methods.

protected static CloudBlobContainer Blob
{
    get { return BlobClient.GetContainerReference(BlobContainerName); }
}
private static CloudBlobClient BlobClient
{
    get
    {
        return Account.CreateCloudBlobClient();
    }
}

Now add code for the table & queue client and reference methods.

protected static CloudQueue Queue
{
    get { return QueueClient.GetQueueReference(QueueName); }
}
private static CloudQueueClient QueueClient
{
    get { return Account.CreateCloudQueueClient(); }
}
protected static CloudTableClient Table
{
    get { return Account.CreateCloudTableClient(); }
}
protected static CloudStorageAccount Account
{
    get
    {
        return
            CloudStorageAccount
            .FromConfigurationSetting("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString");
    }
}

This class now provides the basic underpinnings needed to retrieve the appropriate information from the configuration.  This base class can then provide that connection information to connect to the table, queue, or blob mediums.

Next step is to create some initialization code to get the containers created if they don’t exist in Windows Azure.  Add a new class file to the PutJunkInIt Project.

JunkTrunkSetup

JunkTrunkSetup

public class JunkTrunkSetup : JunkTrunkBase
{
    public static void CreateContainersQueuesTables()
    {
        Blob.CreateIfNotExist();
        Queue.CreateIfNotExist();
        Table.CreateTableIfNotExist(TableName);
    }
}

Next add the System.Data.Services.Client Assembly to the project.  After adding the assembly add two new classes and name them BlobMeta.cs and Table.cs. Add the following code to the Table.cs Class.

public class Table
{
    public static string PartitionKey;
}

Next add another class file and name it BlobMetaContext.cs and add the following code.

public class BlobMetaContext : TableServiceContext
{
    public BlobMetaContext(string baseAddress, StorageCredentials credentials)
        : base(baseAddress, credentials)
    {
        IgnoreResourceNotFoundException = true;
    }
    public IQueryable Data
    {
        get { return CreateQuery(RepositoryBase.TableName); }
    }
    public void Add(BlobMeta data)
    {
        data.RowKey = data.RowKey.Replace("/", "_");
        BlobMeta original = (from e in Data
                                where e.RowKey == data.RowKey
                                    && e.PartitionKey == Table.PartitionKey
                                select e).FirstOrDefault();
        if (original != null)
        {
            Update(original, data);
        }
        else
        {
            AddObject(RepositoryBase.TableName, data);
        }
        SaveChanges();
    }
    public void Update(BlobMeta original, BlobMeta data)
    {
        original.Date = data.Date;
        original.ResourceUri = data.ResourceUri;
        UpdateObject(original);
        SaveChanges();
    }
}

Now add the following code to the BlobMeta Class.

public class BlobMeta : TableServiceEntity
{
    public BlobMeta()
    {
        PartitionKey = Table.PartitionKey;
    }
    public DateTime Date { get; set; }
    public string ResourceUri { get; set; }
}

At this point, everything should build. Give it a go to be sure nothing got keyed in wrong (or copied in wrong). Once assured the build is still solid, add the Blob.cs Class to the project.

public class Blob : JunkTrunkBase
{
    public static string PutBlob(Stream stream, string fileName)
    {
        var blobRef = Blob.GetBlobReference(fileName);
        blobRef.UploadFromStream(stream);
        return blobRef.Uri.ToString();
    }
    public static Stream GetBlob(string blobAddress)
    {
        var stream = new MemoryStream();
        Blob.GetBlobReference(blobAddress)
            .DownloadToStream(stream);
        return stream;
    }
    public static Dictionary<string, string> GetBlobList()
    {
        var blobs = Blob.ListBlobs();
        var blobDictionary =
            blobs.ToDictionary(
                listBlobItem => listBlobItem.Uri.ToString(),
                listBlobItem => listBlobItem.Uri.ToString());
        return blobDictionary;
    }
    public static void DeleteBlob(string blobAddress)
    {
        Blob.GetBlobReference(blobAddress).DeleteIfExists();
    }
}

After that finalize the Table Class with the following changes and additions.

public class Table : RepositoryBase
{
    public const string PartitionKey = "BlobMeta";
    public static void Add(BlobMeta data)
    {
        Context.Add(data);
    }
    public static BlobMeta GetMetaData(Guid key)
    {
        return (from e in Context.Data
                where e.RowKey == key.ToString() &&
                e.PartitionKey == PartitionKey
                select e).SingleOrDefault();
    }
    public static void DeleteMetaDataAndBlob(Guid key)
    {
        var ctxt = new BlobMetaContext(
            Account.TableEndpoint.AbsoluteUri,
            Account.Credentials);
        var entity = (from e in ctxt.Data
                        where e.RowKey == key.ToString() &&
                        e.PartitionKey == PartitionKey
                        select e).SingleOrDefault();
        ctxt.DeleteObject(entity);
        Repository.Blob.DeleteBlob(entity.ResourceUri);
        ctxt.SaveChanges();
    }
    public static List<BlobMeta> GetAll()
    {
        return (from e in Context.Data
                select e).ToList();
    }
    public static BlobMetaContext Context
    {
        get
        {
            return new BlobMetaContext(
                Account.TableEndpoint.AbsoluteUri,
                Account.Credentials);
        }
    }
}

The final file to add is the Queue.cs Class File. Add that and then add the following code to the class.

public class Queue : JunkTrunkBase
{
    public static void Add(CloudQueueMessage msg)
    {
        Queue.AddMessage(msg);
    }
    public static CloudQueueMessage GetNextMessage()
    {
        return Queue.PeekMessage() != null ? Queue.GetMessage() : null;
    }
    public static List<CloudQueueMessage> GetAllMessages()
    {
        var count = Queue.RetrieveApproximateMessageCount();
        return Queue.GetMessages(count).ToList();
    }
    public static void DeleteMessage(CloudQueueMessage msg)
    {
        Queue.DeleteMessage(msg);
    }
}

The now gives us a fully functional class that utilizes the Windows Azure SDK. In Part 2 I’ll start building on top of that using the ASP.NET MVC 2 Web Project. Part 2 will be published tomorrow, so stay tuned.

What You Need and Want With Windows Azure Part II

One of the most useful tools to use in Windows Azure Development is the Windows Azure MMC.  The Microsoft Management Console, or MMC, is the management console that many of the Windows Server Management interfaces can plug into.  The Windows Azure Team has put together the Windows Azure specific MMC Console Plugin that is available for download on Microsoft MSDN Code Site at http://code.msdn.microsoft.com/windowsazuremmc.

 

Windows Azure MMC Code Site

Windows Azure MMC Code Site

 

When you navigate to the page, click on the tab for downloads and you will find three different files;

  • WindowsAzureMMC.exe
  • PerfMon-Friendly Log Viewer Plugin
  • PerfMon-Friendly Log Viewer Plugin (Source Only)

The main file you’ll need to download is the WindowsAzureMMC.exe file.  Once this file is downloaded, run the executable.  An installation wizard will appear, just click next and step through each of the steps accepting any defaults.

 

Windows Azure Management Tool Installation

Windows Azure Management Tool Installation

 

Once the executable runs it should pop up a Windows Explorer Window, if not navigate to where the files where just installed (unzipped) to.  By default the installer places them in C:\WindowsAzureMMC\.  Find the file StartHere.cmd located in the installation directory and fun the file.

 

StartHere.cmd

StartHere.cmd

 

When the file is executed a DOS prompt will flicker, and another configuration wizard titled Windows Azure Management Tools will appear.

 

Configuration Wizard for the Windows Azure Management Tools

Configuration Wizard for the Windows Azure Management Tools

 

Click next and the installation will start, checking each of the dependencies required to execute the MMC.

 

Detecting Required Software

Detecting Required Software

 

Continue to click any next prompts, and then you will have the Windows Azure MMC Console open once the StartHere.cmd finishes executing.  Click close on the configuration wizard.

 

Installation Completed

Installation Completed

 

The MMC will now be displayed on screen as shown below.

 

Windows Azure Management Tool (MMC)

Windows Azure Management Tool (MMC)

 

Open the Windows Azure Management section by clicking on the small tree view arrow on the left hand side.  The tree view will open up to a Service Management Node with a Hosted Services, Storage Services, and Affinity Groups listed underneath the node.  Select the actual Service Management Node so that the middle window shows the connection form shown here.

 

Windows Azure MMC Services Management Node Connection

Windows Azure MMC Services Management Node Connection

 

Now navigate back to Windows Azure Platform Web Interface (http://windows.azure.com).  Click on the project displayed on the main screen to select it.

 

Windows Azure Portland Interface

Windows Azure Portland Interface

 

When the follow page displays, click on the Account tab at the center top of the page.

 

Windows Azure Project

Windows Azure Project

 

When the Account Page finishes rendering look at the very bottom to locate the subscription ID.

 

Windows Azure Project Account Properties

Windows Azure Project Account Properties

 

Enter the subscription ID into the form.  Now click on the ellipsis button on the form so the certificates that are available are displayed.

 

API Certificate

API Certificate

 

Click on the underlined link on the certificate you want to use (sometimes there are a few options, depending on what is installed on the machine already).  A properties dialog should appear when you click on the underlined link button.

 

Certificate Details

Certificate Details

 

Click on the Details Tab on the top of the properties dialog window.

 

Certificate Details, Details Tab

Certificate Details, Details Tab

 

Now click on the Copy to File Button.  An export process will start for the certificate.  Click on next.  On the next screen make sure No, do not export the private key is selected.  The next screen selects the DER encoded binary X.509 (.CER) option.  Verify this setting and then click next.

 

Certificate Export Wizard

Certificate Export Wizard

 

Click on next and then enter the path and filename where you want to save the certificate.

 

Save As File Name for Certificate

Save As File Name for Certificate

 

Now that you have the certificate, return to the Windows Azure Platform Web Interface (http://windows.azure.com).  Navigate to the Account Tab section of the site again.  On that page click on the Manage My API Certificates.  This is the same page as shown above in the image captioned “Windows Azure Project Account Properties“.  Once the page displays click on the Choose File button on the page.  Find the location the certificate was saved and select the certificate.  Now click the upload button to upload the file to the Windows Azure Account.

 

API Certificates Upload

API Certificates Upload

 

When the file is done uploading the page will update and show something similar to what is shown in the next screenshot.

 

API Certificates, Finished Uploading

API Certificates, Finished Uploading

 

Now you can click on the OK button, if you haven’t already, to confirm the API Certificate in the Windows Azure MMC.  Click on the Connect button in the far right window area of the MMC.  It should take a second but the connection should occur.  You can tell by the Default storage account form drop down becomes enabled.  At this time though, since we haven’t placed anything in storage or started any storage services there will be nothing displayed in the drop down.

At this point the MMC is functional; there just isn’t much to look at in the Windows Azure Account yet.  So let’s change that and setup some sample services.  First head back over to the Windows Azure Platform Web Interface (http://windows.azure.com).  Once you’re in click on the project as we did before so that it is the focus point.  Click on the +New Service link in the top right of the main page window section.

 

Starting a Windows Azure Service

Starting a Windows Azure Service

 

The next screen will display the options to create a Windows Azure Storage Account or a Hosted Services Role.  Click on the Windows Azure Storage Account option.

 

Windows Azure Create a Service

Windows Azure Create a Service

 

On the screen that renders fill out the service label and description.  Both of these fields are mostly free text, allowing spaces and special characters.  Click next when you have filled out the label and description.

 

Services Properties

Services Properties

 

The next form that comes up has the public storage account name.  This field must be compliant with URI naming conventions.  The idea also is that these storage services use a RESTful API, it is best to follow the REST Architecture ideals and name the location something easy to read and to remember.  You can click the check availability button to verify if the name is used or not.  If it is available move down and select Anywhere US for the region.

 

First Storage Sample

First Storage Sample

 

Once you are finished click the create button at the bottom of the form.  The next window will render the results of creating the Windows Azure Storage Account.  This page has all the information you’ll need to fill out the Windows Azure MMC connection information.

 

Windows Azure Storage Account Properties

Windows Azure Storage Account Properties

 

If you still have the Windows Azure MMC open, bring focus to it again.  If not open it back up and open the Windows Azure Management tree view back to the Service Management Node and verify or enter the information for the subscription ID and API Certificate.  Now click on the Connect link button on the right hand window pane.  The MMC will then connect and will populate the Default storage account drop down.  Click on the drop down and you will see your Windows Azure Storage Account that we just created.

 

Service Management Node Connected with Default Storage Account

Service Management Node Connected with Default Storage Account

 

Now that we have a Windows Azure Storage Account, let’s get a Windows Azure Services Role running also.  Navigate back to the Windows Azure Platform Web Interface (http://windows.azure.com).  Once the page has rendered click on your specific project, wait for that page to render and  then on the +New Service link. This time select the Windows Azure Services Role to create.  On the next page fill out the service label and description the same as with the Windows Azure Storage Account creation.

 

Create a Service (Role)

Create a Service (Role)

 

Click next when complete.  On the next page that renders you’ll again pick a public URI subdomain path, which I’ve used firstservicesample as mine, and select Anywhere US from the drop down for the region.  Click on the create button when complete.  The following page will display with a single cube image in the center of the screen, label Production.  For now, the instance role is available, but nothing is deployed and nothing is being charged at this time.  However this is perfect for checking out the Windows Azure MMC display of the services.

 

Service Role

Service Role

 

Return to the Windows Azure MMC and click on the Hosted Services node.  Click on Connect in the right hand window pane under actions.  The firstservicesample node, or whatever you may have named the service, will display with the staging, production, and certificates nodes appearing below.  From here you can deploy, upgrade, run, delete, suspend, swap, or even save the configuration of your roles.  This is extremely helpful so that one doesn’t always need to return to the site and can maintain multiple hosted services, storage services, affinity groups, and more from the MMC.

 

Windows Azure Staging

Windows Azure Staging

 

Next let’s click on the Storage Explorer Node just below the Service Management Node.  Click on New Connection and enter the Account Name as shown below.

 

New Account Form

New Account Form

 

Now that the account name and URIs are filled out.  Return to the storage services properties page in the Windows Azure Platform Web Interface (http://windows.azure.com).

 

Windows Azure Storage Account Properties

Windows Azure Storage Account Properties

 

On this page you’ll find the key you need to finish off the form in the Windows Azure MMC.  Once you’ve completed the form click on OK.  The MMC should now populate out the cloud storage account area with a node for BLOB Containers.

 

Storage Account Services

Storage Account Services

 

Click on the BLOG Containers so and click on Add Container in the right hand side window pane under actions.  Enter a name, in this case I entered musicmanager, and click OK.  Now you should have a BLOB Storage Container in your Windows Azure Storage Account.

 

Windows Azure BLOB Container

Windows Azure BLOB Container

 

Click on the musicmanager BLOB Container, or whatever you named yours, and then click on Upload BLOB under the actions window on the right hand side.  Select a file, I’ve chosen a music MP3 I have on my local machine.

 

Uploading a BLOG File (A Music MP3)

Uploading a BLOG File (A Music MP3)

 

Click OK and you’ll see the Operations queue node on the lower left hand side of the Console Root tree view populate with the upload activity task.

 

The Upload in the Operations Queue

The Upload in the Operations Queue

 

After the upload is complete the BLOB Container will then show the BLOBs just below it when selected in the Windows Azure MMC.