次の方法で共有


Beginning Azure - Part 2 Initializing Storage And the WCF Role.

Hi All,

Alright, so lets start digging into some code and explanation as to what is going on here and why we are doing some things.  Also I will point out pitfalls and difficult to find problems that you will probably run into.  Feel free to post more comments regarding any questions or problems that you ran into and I will do my best to hunt down the solution and post it back to this blog.

Step 1 - Get the SDK

The first thing you should do is (if you haven't already) is to download the latest and greatest Azure SDK.  The easiest way to do this and get everything you need is to:

  1.  Open Visual Studio 2010

  2.  Click New Project -> Cloud Project, and name it whever you feel like.

  3.  If the download does not start immediately, click Install and follow the typical install buttons.

  4.  Alternatively you can download from here and pick your language(s) of choice: https://www.windowsazure.com/en-us/develop/overview/

 

Step 3 - Create the New Project

So this project is going to be JUST Azure.  Front-end agnostic.  You can choose to host your front end on Azure if you like, and that is covered well by the templates, and other tutorials.  I am covering JUST Azure, and how to link that project up to a Silverlight or other Front End.

  1.  So click File -> New Project.  Under Visual C# there is a section for Cloud (where you went to install the SDK), and Select Windows Azure Project.  Name it whatever you feel like.

  2.  Select to add a WCF Role and a Worker Role.  These two roles are your bread and butter for Azure.  If you don't learn anything else these two are what I feel to be the most important.  Especially if your targeted audience is consuming apps that are hosted locally and not web sites, or web applications stored on Azure(example, phone apps or Windows 8 Apps).

 

Step 4 - Write The WCF Service Part 1

So I am a strong beleive in "If I provide you everything, you will learn nothing".  I am going to provide the important peices for Azure, the plug and play parts to get YOUR project up and going, not my silly sample. 

  1.  The first thing to do here is to Right Click WCFServiceWeb Role1 (project) and click Add New Item.  Select Global Application.  It will Add a Global.asax and Global.asax.cs files to your WCFServiceWebRole1 project at the root level.

  2.  Then modify the On Start Event, add the following code into the Global.asax.cs class.

protected void Application_Start(object sender, EventArgs e) {    CloudStorageAccount.SetConfigurationSettingPublisher((configname, configSetter) => configSetter(RoleEnvironment.GetConfigurationSettingValue(configname))); }

So What the heck does that do?  Why do I need that code?  Well sirs and ma'ams, this is one of those magic lines of code that was hard to figure out.  This line of code pulls down your settings from your Azure settings (we will get into that in a bit), and basically tells any applications on this virtual machine (all roles are broken down into virtual machines), hey, use these settings.  It will save you time from hunting down whats going on.  The ensure you called SetConfigurationSettingPublisher first error.  If you follow the MVC tutorials, often times you you see this being set in the Worker role, but not in the front end role, because I guess it just got left out of the tutorial on accident.  Anyways, thats the first thing.  Make sure that your WCF role has the global configuration settings set in your account.

For those who have not seen this syntax before, please read the following: https://msdn.microsoft.com/en-us/library/bb549151.aspx  What that says is basically, Im going to store this method in memory for later use.  This is just a more complicated variation.

So now that we have the Configuration settings set, lets do something!

Step 5 - Write the WCF Service Part 2

  1.  So Lets just start with the typical WCF stuff starting with IService1.cs.  Looks pretty standard.  BECAUSE IT IS!!!!  Isn't this great, pretty much everything you knew about WCF is the same.  So nothing Azure related to note here for base cases, so lets move on :D.

  2.  So lets check out our implementation of IService1, Service1.svc.cs.  Ah, now here is some more Azurey stuff to do.  Lets first talk about our private fields, for the more humorous of my readers, we are not talking about THOSE private fields, but rather, these private fields:

namespace WCFServiceWebRole1 { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ArticleService" in code, svc and config file together. public class ArticleService : IArticleService { private static CloudBlobClient blobStorage; private static CloudQueueClient queueStorage; private static object gate = new object(); private bool storageInitialized = false;

So what is all this stuff?  Well lets step through this a second.  CloudBlobClient blobStorage is an object that essentially gives you access to everything you need to deal with the Blob.  containers, uploading, etc etc.  The CloudQueueClient is the same thing, just for the queue.  So what is gate?  More or less this is just to keep concurrent users from messing with and changing blobStorage or queueStorage at the same time, or trying to initialize them.  Just wanna do that once.  Storage initialized...well it means it hasn't happened yet.  Gotta do it, and thats what is next!

 

Step 6 - Write the WCF Role part 3

So before you do any messing around with the storage, reading, writing, whatever you want to do with your Azure storage, you need to initialize it.  Its typically a frowned upon practice to do anything with storage before you initialize it.  So lets just take a look at what that code looks like, and I'll give an explanation behind it.

 private void initializeStorage() { if (storageInitialized) return; //create a lock on the initialization process just in case there are concurrent attempts to access. lock (gate) { if (storageInitialized) return; 

The first thing we do is to check to see if the storage is an initialized.  If it is, well get out of here, its already done. 

If not, lets lock the gate. Now some of you may say "why check to see if its initialized again, wouldnt that not happen, well lets assume the following case, since this is potentially a multithreaded concurrent situation trying to access static objects.

Thread A, Thread B

Thread A and B both Check to see if initialized, and it is not, so now we get to Lock.  Thread A Locks Thread B sits on the Lock waiting for A to release it.  Thread A completes and sets Initialized to true.  Thread B gets the lock and enters the loop.  Check to see if initialized, it is, lets peace out.

try
{

//read account configuration settings
var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

//create blob container for articles
blobStorage = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobStorage.GetContainerReference("lowercaselettersonly");
container.CreateIfNotExist();
 

 So lets look at this code.  Throw everything in a try catch just in case, this can cause problems, so you want to catch the exception and be able to do something with it.  One of the areas AND THIS IS A COMMON ISSUE.  is the first line, where you draw from the configuration settings.  Remember that delegate and that confusing syntax above?  Yeah, if you don't do that, this line will blow up on you in any class that makes this call.  So its good to have that in a global class so all these classes have access to it.

So the next 3 lines...you create the blobStorage class based on the account settings.  These settings are things like your instance size, the number of instances, etc etc.  So you initialize that.  Then you need to create a container.  The container is an object that gives you access to the different container types for blob storage, block, meta data, and a plethora of other things that we don't care about right now.  Notice the reference.  This is the reference name that you will always reference this container by.  Notice how the name is in ONLY LOWER CASE LETTERS.  This is very important.  If it is anything other than lower case letters, symbols etc etc, it WILL blow up on you and throw you errors.  read more here:

https://blogs.msdn.com/b/windowsazure/archive/2010/12/08/how-to-resolve-setconfigurationsettingpublisher-needs-to-be-called-before-fromconfigurationsetting-can-be-used-after-moving-to-windows-azure-sdk-1-3.aspx

the next nice thing is, just in case you created it before, there is a nice method that creates it IF it doesn't exist.  If it does, it just does nothing.  So some more lines of code for permissions.  Because we beleive strongly in security.

//configure container for public access
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);

So what is going on here?  Essentially we are setting the permissions so that any anonymous clients can read our blob and container.  Probably not the best thing to do.  I would suggest taking a look at the below link since they explain fairly well.  I would also suggest reading MSDN on permissions as well.

https://allcomputers.us/windows_azure/blobs---setting-shared-access-permissions.aspx

https://msdn.microsoft.com/en-us/library/windowsazure/microsoft.windowsazure.storageclient.blobcontainerpermissions.aspx

 //create queue to communicate with worker role queueStorage = storageAccount.CreateCloudQueueClient(); CloudQueue queue = queueStorage.GetQueueReference("workermessages"); queue.CreateIfNotExist();

So lets take a look at this code here.  This code initializes the Queue from the storage account settings from the begining.  Similiar process to initializing the blob.  We then build the queue.  exactly like we build a container because it is basically a blob container, but for a queue :D.  Wasnt that nice of them.  And of course we create it if it does not exist.  Notice again that the reference is ALL LOWER CASE LETTERS!  REMEMBER THAT...it will save you time debugging a very cryptic error.

So lets finish up here by catching any exceptions and setting storage initialized to true;

        }
                catch (Exception e)
                {
                    throw new Exception("Storage services initialization failure.  "
                        + "Check your storage account configuration settings.  If running locally, "
                        + "ensure that the Development Storage service is running.");
                }

                storageInitialized = true;

     }

}

So that is how to first set up your WCF Role and also initialize your storage.  Part 3 will be inserting items into Blob storage with a break down line by line what is actually going on.  So by the end of Part 3 you should be able to have a new Azure project with a functional WCF role that fills up your data from anonymous clients (make sure you don't just copy paste this code for initialization and make sure you set up some tighter security, this is demo purposes only to get you up and running with Azure).

~Dave

Feel free to post questions, leave feedback, ask questions.  If you find anything inacurate in the article let me know and I will fix it upon verification.

 

********************************************************************************************************************

So for conveniences sake Im going to go ahead and copy/paste the code for the entire initialization method.  Here it is below.

        private void initializeStorage()
        {
            if (storageInitialized)
                return;
            //create a lock on the initialization process just in case there are concurrent attempts to access.
            lock (gate)
            {
                if (storageInitialized)
                    return;
                try
                {
                   
                    //read account configuration settings
                    var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

                    //create blob container for articles
                    blobStorage = storageAccount.CreateCloudBlobClient();
                    CloudBlobContainer container = blobStorage.GetContainerReference("articleblob");
                    container.CreateIfNotExist();

                    //configure container for public access
                    var permissions = container.GetPermissions();
                    permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                    container.SetPermissions(permissions);

                    //create queue to communicate with worker role
                    queueStorage = storageAccount.CreateCloudQueueClient();
                    CloudQueue queue = queueStorage.GetQueueReference("workermessages");
                    queue.CreateIfNotExist();
                }
                catch (Exception e)
                {
                    throw new Exception("Storage services initialization failure.  "
                        + "Check your storage account configuration settings.  If running locally, "
                        + "ensure that the Development Storage service is running.");
                }

                storageInitialized = true;
            }

        }