Building in the Cloud with Azure Storage and the Azure SDK, Page 3
Click here for larger image
Figure 1.5 Development Storage After Creating Table
You are now ready to add code to the
"Default.aspx.cs" file so that new Calculation
objects can be created and saved to the Table storage. This
will be done by adding code to both the
Page_Load method and to the start calculation
button's click event handler.
using Microsoft.Samples.ServiceHosting.StorageClient;
using System.Data.Services.Client;
// ...
protected void Page_Load(object sender, EventArgs e)
{
try
{
StorageAccountInfo accountInfo = StorageAccountInfo.GetAccountInfoFromConfiguration("TableStorageEndpoint");
// Not required in development since the table is created
// manually but is needed in the cloud to create the tables
// the first time.
TableStorage.CreateTablesFromModel(typeof(CalculationDataServiceContext), accountInfo);
}
catch (DataServiceRequestException ex)
{
// Unable to connect to table storage. In development
// verify the service is running. In the cloud check that
// the config values are correct.
// Handle error
}
}
protected void cmdStartCalculation_Click(object sender, EventArgs e)
{
StorageAccountInfo accountTableInfo = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();
CalculationDataServiceContext calculationDSContext = new CalculationDataServiceContext(accountTableInfo);
lblCalculationKey.Text =
calculationDSContext.AddCalculation(int.Parse(txtValueOne.Text), int.Parse(txtValueTwo.Text));
lblCalculationKey.Visible = true;
}
When you run the application now, you will be able to
enter two values, store them to Table storage and return the
RowKey so it can be later retrieved. The next
step will be to send a message to the Worker Role via Queue
storage to retrieve the values and add them together.
Using Windows Azure Queue Storage
To send a message to the Work Role you will first need to
insert code to the "Default.aspx.cs" file to
add the message to the Queue. The code needs to be added in
the same button click event as when the Calculation object
is created and the RowKey is returned. The
Worker Role will need to know both the
PartitionKey and RowKey to
retrieve the correct values to perform the calculation. For
this example the PartitionKey is hardcoded to
"TEST" so you only need to pass the RowKey. In
a more robust application you would most likely have to pass
both values for the Worker Role to be able to retrieve a
unique record.
Default.aspx.cs (Part 2)
protected void cmdStartCalculation_Click(object sender, EventArgs e)
{
// ...
StorageAccountInfo accountQueueInfo = StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration();
QueueStorage qs = QueueStorage.Create(accountQueueInfo);
MessageQueue queue = qs.GetQueue("calculations");
if (!queue.DoesQueueExist())
queue.CreateQueue();
Message msg = new Message(lblCalculationKey.Text);
queue.PutMessage(msg);
}
The next step is to open the "WorkerRole.cs"
file and add the code that retrieves the message from the
Queue storage, performs the calculation and updates the
entity in Table storage. To do this the following code needs
to be added to the Start method of the
"WorkerRole.cs" file.
WorkerRole.cs
using Microsoft.Samples.ServiceHosting.StorageClient;
// ...
public override void Start()
{
RoleManager.WriteToLog("Information", "Worker Process entry point called");
// Create account info objects for retrieving messages and accessing table storage
StorageAccountInfo accountTableInfo = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();
StorageAccountInfo accountQueueInfo = StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration();
CalculationDataServiceContext calcDSContext = new CalculationDataServiceContext(accountTableInfo);
QueueStorage qs = QueueStorage.Create(accountQueueInfo);
MessageQueue queue = qs.GetQueue("calculations");
while (true)
{
Thread.Sleep(10000);
if (queue.DoesQueueExist())
{
Message msg = queue.GetMessage();
if (msg != null)
{
// Retrieve the Calculation entity from Table storage
var calc = (from c in calcDSContext.Calculations
where c.PartitionKey == "TEST"
&& c.RowKey == msg.ContentAsString()
select c).FirstOrDefault();
if (calc != null)
{
calc.CalcValue = calc.ValueOne + calc.ValueTwo;
// Update the entity with the new CalcValue
// property populated
calcDSContext.UpdateObject(calc);
calcDSContext.SaveChanges(SaveChangesOptions.ReplaceOnUpdate);
// Need to delete the message once processed!
queue.DeleteMessage(msg);
}
}
}
}
}
You now have a functioning Worker Role that is going to check the "calculation" queue for messages every 10 seconds. When it finds a message it retrieves the corresponding Calculation entity from Table storage, updates the calculated value property and then updates it back to Table storage. The last and important thing that happens is the message is deleted from the queue so it is not retrieved again.
