93 { return RoleStatus.Healthy; } private void Initialization { if initialized { return; } lock syncObj { try { //Instatiate BlobStorage blobStorage = BlobStorage.Creat
Trang 193
{
return RoleStatus.Healthy;
}
private void Initialization()
{
if ( initialized)
{
return;
}
lock ( syncObj)
{
try
{
//Instatiate BlobStorage
blobStorage =
BlobStorage.Create(StorageAccountInfo
GetDefaultBlobStorageAccountFromConfiguration());
blobContainer =
blobStorage.GetBlobContainer(WorkerRole.PAYLOAD BLOB CONTAINER NAME); // Make the container public so that we can hit the URLs from the web
blobContainer.CreateContainer(new NameValueCollection(),
ContainerAccessControl.Public);
//Instatiate QueueStorage
queueStorage =
QueueStorage.Create(StorageAccountInfo
GetDefaultQueueStorageAccountFromConfiguration());
queueStorage.RetryPolicy =
RetryPolicies.RetryN(3, TimeSpan.FromSeconds(5));
//Create a queue to listen blob create request message
//and register the events
MessageQueue requstQueue =
queueStorage.GetQueue(PAYLOAD CREATE REQUEST QUEUE NAME);
requstQueue.CreateQueue();
requstQueue.MessageReceived +=
new MessageReceivedEventHandler( OnCreateBlobMessageReceive);
requstQueue.PollInterval = POLLING INTERVAL;
requstQueue.StartReceiving();
//Create a queue without to register any event to send the blob created
//message with blob name to the queue
MessageQueue resultsQueue =
queueStorage.GetQueue(PAYLOAD RESULTS QUEUE NAME);
resultsQueue.CreateQueue();
//Create a queue to listen blob delete request message
//and register the events
MessageQueue deleteQueue =
Trang 294
queueStorage.GetQueue(PAYLOAD DELETE QUEUE NAME);
deleteQueue.CreateQueue();
deleteQueue.MessageReceived +=
new MessageReceivedEventHandler( OnDeleteBlobMessageReceive);
deleteQueue.PollInterval = POLLING INTERVAL;
deleteQueue.StartReceiving();
initialized = true;
}
catch (Exception ex)
{
LogError(
string.Format(
" - {0}: Initialization, exception caught : {1}",
this.ToString(),
ex.Message
)
);
}
initialized = true;
}
}
private void CreateBlob(Message message)
{
lock ( syncObj)
{
string logMessage =
string.Format(
" -{0}: OnMessageReceive, message = <{1}>",
this.ToString(),
message.ContentAsString()
);
System.Diagnostics.Trace.WriteLine(logMessage);
Log(logMessage);
string blobName = string.Format("{0}{1}", message.Id, PAYLOAD BLOB SUFFIX);
if (! blobContainer.DoesBlobExist(blobName))
{
// Compose a unique blob name
BlobProperties properties = new BlobProperties(blobName);
// Create metadata to be associated with the blob
NameValueCollection metadata = new NameValueCollection();
metadata["MediaID"] = message.Id;
properties.Metadata = metadata;
properties.ContentType = "text/xml";
Trang 395
// Create the blob
byte[] buffer =
UTF8Encoding.UTF8.GetBytes(
message.ContentAsString().Replace("\r\n", string.Empty)
);
MemoryStream ms = new MemoryStream(buffer);
BlobContents blobContents = new BlobContents(ms);
blobContainer.CreateBlob(properties, blobContents, true);
var blob = (from m in blobContainer.ListBlobs(string.Empty, false)
where (m as BlobProperties).Name == blobName
select m as BlobProperties).Single <BlobProperties>();
if (null != blob )
{
MediaInfo mediaInfo =
new MediaInfo(
blobName,
(blob as BlobProperties).Uri.ToString(),
message.Id
);
Message resultsMessage = CreateMediaInfoMessage(mediaInfo);
MessageQueue queue =
queueStorage.GetQueue(PAYLOAD RESULTS QUEUE NAME);
queue.PutMessage(resultsMessage);
}
}
queueStorage.GetQueue(PAYLOAD CREATE REQUEST QUEUE NAME)
DeleteMessage(message);
}
}
private void OnCreateBlobMessageReceive(object sender, EventArgs args)
{
lock ( syncObj)
{
CreateBlob((args as MessageReceivedEventArgs).Message);
}
}
private Message CreateMediaInfoMessage(MediaInfo info)
{
StringBuilder sb = Helper.XmlPersist(info, typeof(MediaInfo));
return new Message(UTF8Encoding.UTF8.GetBytes(sb.ToString()));
}
private void OnDeleteBlobMessageReceive(object sender, EventArgs args)
{
lock ( syncObj)
{
Trang 496
Message message = (args as MessageReceivedEventArgs).Message;
string blobName = message.ContentAsString();
Log(
string.Format(
" -{0}:received delete blob request, blob name = <{1}>",
this.ToString(),
blobName
)
);
if ( blobContainer.DoesBlobExist(blobName))
{
Log(
string.Format(
" -{0}:delete blob request, blob name = <{1}>",
this.ToString(),
blobName
)
);
blobContainer.DeleteBlob(blobName);
}
queueStorage.GetQueue(PAYLOAD DELETE QUEUE NAME).DeleteMessage(message); ; }
}
}
}
Compiling the code and running the application, we get the same results with this new architecture design as Figure 3-8 shown in the last exercise
Through this exercise, we have actually built a template for a cloud application that can be used as a communication bus between the web roles and worker roles This is the solution to decouple a web role from a worker role Since a worker role cannot expose its end point, it cannot accept external HTTP requests We can leverage the queue as the message bus to build the communication bridge between a web role and worker role In fact Azure uses the same approach to decouple its front-end services to increase efficiency and performance
Implementing a Client Application to Access Cloud Blob
Storage
If we need to upload or delete a large amount of data from cloud blob storage in a client-side
application, we should consider not only using an asynchronous approach to handle the task in a background thread, but also supporting manually interruption if something goes wrong, which may be caused by network failure or other reasons since Azure blob storage handles transactions on the server side, not on the client side
Under the hood, the SDK client wrapper dispatches the request by calling two different overloaded handler methods based upon the size of the data If the data size is greater than 2 MB, the data will be processed through the large data upload hander from the Azure storage client The Azure blob storage client may contact a group of connected servers in the cloud based upon the balance of the server load
Trang 597
The contents will be split into numerous data blocks and spread to multiple servers The Azure blob
storage client will call a method to commit the transaction If any process fails or an interruption occurs, the transaction will not be committed
This exercise provides a workaround to resolve uploading and downloading a large amount of blob data on the client side This application may potentially be used as a utility tool for anyone who needs to transmit a large amount of data to a cloud blob In this exercise we will walk you through creation of a
Windows-based tool that can be used to upload and delete large amounts of data from cloud blob
storage
■ Note The code for this example is in the Exercise 3-4 bundle from the code download
There are two technologies for handling large amounts of data, especially data transmission over the network:
• Asynchronous data transmission
• Background worker item thread
The NET Framework provides extensive support for these two technologies, such as a thread pools and a background worker class This exercise uses these two technologies in conjunction with other
software design patterns, such as the command and facade design patterns to come up with a useful
client-side tool to handle large data I/O to Azure blob storage At the highest level, we define two
modules: AzureStorageFacade and BlobStorageActionStatus The responsibilities of these two classes are
as follows
• AzureStorageFacade is an abstract base class that wraps the class of the Azure
storage SDK client The responsibility of the base class is to instantiate the Azure
account object, including the authentication key information We are going create
two classes called BlobStorageFacade and TableStorageFacade that will inherit
from this class BlobStorageFacade encapsulates the blob container and blob
properties objects used to access a specific named blob storage from the cloud
This class provides an agile way to perform insert and delete actions to blob
storage (update can be done by changing the overwrite flag to false) To reach
this goal, the constructor of this class accepts three parameters of blob storage:
BlobContents, BlobProperties, and a boolean flag of overwrite
• BlobStorageActionStatus is an abstract base class This class uses a combination
of the bridge design pattern and the command design pattern (without supporting
the memento pattern, because there is actually no transaction supported from the
client side in the cloud platform The constructor of this class has exactly the same
structure as that of BlobStorageFacade The responsibility of this class is to spawn
a worker thread to handle the long-running blob storage access tasks and to
provide the progress status of the data access BlobStorageActionStatus has two
derived classes, CreateBlobStatus and DeleteBlobStatus, which are responsible
for blob storage creation and deletion respectively All derived classes implement
the ICommand interface, which provides an Excuse() function to update the
progress status