Patterns-Based Silverlight Development – Part I – Getting Started
Introduction
During the summer I put together a session on Patterns-Based Silverlight Development that we delivered across the West Region as part of MSDN events. The session was structured around building a Silverlight application from the ground up that illustrated the use of the following design patterns: 1) Repository, 2) Pipeline, 3) Service Agent and 4) Model View ViewModel. The goal was not to build a final productionized version of the application, rather illustrate how one might take advantage of these patterns in a Silverlight application. I will follow the same plan here, albeit in more detail.
Environment and Demo Choices
Development Environment:
- Visual Studio 2008 sp1
- .NET Framework 3.5 sp1
- Silverlight 3
- The Silverlight 3 tools for Visual Studio 2008 sp1
- The Silverlight 3 Toolkit – July 2009 drop
* There is no reason you wouldn’t be able to follow along using our free tools
Demo Choices:
Whenever you put together a sample application, you have to make some choices: Language, Web Services Stack, REST vs. SOAP, data access strategy, etc. The following is a listing of some of the choices I made for this sample to start with (I may swap in and out as things progress):
- Language: C#
- Data Access: LINQ to SQL – This was a random decision. I had done a bunch of work with the EF lately. Thought I’d give it a go. I may swap this layer out later for the EF when .NET 4 hits Beta 2
- Web Services: WCF, SOAP, New custom Silverlight binding
Setting up the Project
I set up Visual Studio to use solution folders to clearly illustrate what is server code and what is client code. Here is what it will look like eventually:
We are going to start with creating a blank solution and add the 2 solution folders. We will then add the HelpDesk.Data project to the Server solution folder.
- Create a blank solution
- On the File menu, select New and then click Project
- Under Project types, select Other Project Types and then select Visual Studio Solutions
- Select Blank Solution
- Name it HelpDesk
- Add the ‘Client’ and ‘Server’ solution folders
- Right-Click on the Solution
- Choose Add -> New Solution Folder -> Name it ‘Client’
- Repeat for ‘Server’
- Add the HelpDesk.Data class library
- Right-Click on the Server solution folder
- Choose Add -> New Project
- Under Windows -> Choose Class Library
- Name it HelpDesk.Data
- Delete Class1
Data Model
I am using a VERY simple data model I crufted up. There is a Ticket table with a SeverityLevel Lookup table. See below:
Building the LINQ to SQL Model
I assumed that this part of the application would take under 5 minutes. As it turns out, that was a poor estimate. The issue I had surrounded serializing the generated L2S objects. It took me hours to realize that the Visual Studio designer did not support configuring the serialization in the way I needed it (at least I couldn’t figure it out). Truthfully, I could have skipped all of that pain and manually decorated the classes with the appropriate attributes up front, but I wanted to use the designer, if for no other reason than it would save me from re-decorating the classes every time I re-generated the classes. In the end, I was able to get partway there with the designer, but did have to make a change in the code, as well. Let’s walk through the process:
Adding the Tables to the Designer
- Add a LINQ to SQL named HelpDesk.dbml to the HelpDesk.Data project.
- Right-Click the HelpDesk.Data project –> Add –> New Item
- Choose Visual C# Items –> Data –> LINQ to SQL Classes
- Name it HelpDesk.dbml
- Add the ‘Ticket’ and ‘SeverityLevelLookup’ tables to the L2S designer
- From the ‘Server Explorer’, expand the Tables Node from the HelpDesk Database
- Drag the ‘Ticket’ and ‘SeverityLevelLookup’ tables onto the designer
- Make some simple adjustments to the model
- Rename the ‘SeverityLevel’ property to ‘Level’
- Rename the ‘SeverityLevelLookup’ Class to be ‘SeverityLevel’
Configure the Classes to be Serializable
By default the “Serialization Mode” for the Model is set to None:
What does that mean? Well, the default serializer for WCF is the DataContractSerializer. When it was first released (Fx 3.0), it required you to apply the DataContractAttribute to classes you wanted to serialize and to apply the the DataMemberAttribute to fields and properties you wanted to be serialized. WCF 3.5 sp1 lifted this restriction, allowing for the serialization for POCOs (Plain Old C# CLR Objects). The Serialization Mode of None simply indicates that the designer will not add any DataContractAttributes or DataMemberAttributes to your classes or properties, respectively.
Do I really need to decorate my classes? I mentioned POCO serialization support. The reality is that if you have any relationships between your classes, you will need to decorate your classes. So the first step is to set this Serialization Mode to Unidirectional. Incidentally, you can click on the properties pane and then click on any white space in the designer to view the properties for the DataContext.
This means that the classes in the model will be decorated with a DataContractAttribute and some public properties will be decorated with a DataMemberAttribute. So which properties are decorated. To start with, all, public primatives will be decorated. What we have to now understand is which complex types will be decorated. This is where the term ‘Unidirectional’ takes on importance. Essentially, if you take a look at the generated classes, the SeverityLevel class contains a collection of Tickets and the Ticket class has a SeverityLevel object. Hopefully, you can see that if we serialized both sides of the relationship, we will create an endless loop. What Unidirectional then means is that we will support serializing one side of the relationship. By default, by choosing Unidirectional, we will serialize the parent class and the child collection. So, in this case, if we serialize the SeverityLevel class, we will by default serialize it’s collection of Tickets. Have a look at the designer (I clicked on the relationship arrow in the designer):
If you take a look at the HelpDesk.designer.cs file, you can see the actual code that gets generated.
Notice below that the Tickets collection is decorated with a DataMemberAttribute in the SeverityLevel class. Also notice that the SeverityLevel property is not decorated in the Ticket class.
This default behavior does not suit the needs of my application. It does not make sense to fetch a particular SeverityLevel (like Low, Medium or High) and with it a collection of Tickets. It does, however make sense to return a SeverityLevel type when fetching a Ticket. I need to change the direction of serialization. This is the point where spent all of my time. I was not able to find the appropriate settings in the designer to accomplish this task. Clearly, I could have simply taken the 30 seconds to delete the DataMemberAttribute above the Tickets property and added one above the SeverityLevel property. However, as I stated, every time the code was regenerated, I would have to remember to make this change. (*** It is highly likely that there is a way to do accomplish this in the designer. If you know how, please leave me a comment and I will update this post ***).
I was able to get partially there in the designer. By setting the Child property to ‘Internal’, I was able to prevent the Tickets collection from being decorated:
That left decorating the SeverityLevel property in the Ticket class. I simply did that manually. Now my LINQ to SQL model is ready to go.
What’s Next
Tomorrow I will build a repository layer and illustrate the value of that pattern.
Introducing Parallelism into your programs
Overview
A little over a month ago, I volunteered to develop a session for the Windows 7 / Windows Server R2 launches that are being delivered across the country and beyond The session I worked on I affectionately call “An Introduction to Parallel Programming”. In that session I wanted to illustrate various approaches you can take when introducing parallelism to your applications: 1) Fine-grained parallelism, 2) Structured parallelism and 3) PLINQ.
The approach I chose was to start with an a sequential application and parallelize it using each of the 3 approaches. The application I wrote simply creates a thumbnail image for every image in a specific directory. This post provides a link to a screencast I did on this subject, provides a brief overview of each approach and illustrates how my sample program looks with each approach.
Screencast
Click here to view the screencast on channel9
Approaches for introducing parallelism into your applications
Fine-grained parallelism (aka imperative task parallelism)
This approach provides you with the most control. Accordingly it requires the most work. The following are some attributes of this approach:
- Express potential parallelism via expressions and statements that take the form of lightweight tasks
- Affords fine-grained control
- The semantic is similar to how threads and the threadpool work today
- You tend to use it when the other approaches do not suit your problem
Structured parallelism (imperative data parallelism)
Structured parallelism offers a higher level of abstraction. With this approach you tend to think in terms of parallelizing ‘blocks of code’. Daniel Moth did a great job of explaining this in his PDC 08 talk this way: One thread goes into that block. Within that block, many threads can execute the code within the block and one thread comes out. To this end, we provide a ‘Parallel’ type that allows you to easily parallelize for loops, foreach loops and arrays of actions. The following are some attributes of this approach:
- Mechanisms used to express common imperative data-oriented operations
- For loops
- Foreach loops
- Invoke
- Think in terms of blocks of code
- Parallelize loops
PLINQ (Declarative Data Parallelism)
As a declarative approach, you simply define what you want done, not how you want it done. You do this with PLINQ, an implementation of LINQ To Objects. PLINQ replaces LINQ to Objects extension methods with new ones that internally use parallelism. In many cases, it is as simple as adding a call to the AsParallel extension method to your query. The following are some attributes of this approach:
- Implementation of LINQ-to-Objects that executes queries in parallel
- Express what you want to accomplish, rather than how you want to accomplish it
- Minimal impact to existing queries
Illustrating the 3 Approaches
In order to illustrate these 3 approaches, I decided to take a simple console application that was implemented sequentially and convert it to use each approach. The sample application simply creates a thumbnail image for each image in a specified directory. The process I will take is to show you the code for the sequential implementation, as well as each approach to parallelism. I will then explain the code and lastly show you the timings for each approach. I am running this on a dual core laptop using the Beta 1 of Visual Studio 2008 and .NET 4. I will run the code 3 times for each approach.
* Please note that the results in this post should not be used to evaluate which of the 3 parallel approaches is generally more performant than the others. That will be scenario driven. The numbers should simply be used to illustrate the relative performance gains the parallel approaches provide over the sequential approach.
The Sequential Version of the application
The Code
The following is the serial version of the application:
static void Main(string[] args) { Stopwatch sw = Stopwatch.StartNew(); CreateThumbnails(); Console.WriteLine("Elapsed = " + sw.ElapsedMilliseconds.ToString()); Console.ReadLine(); } private static void CreateThumbnails() { string[] pics = Directory.GetFiles(imageDir, imageExt); foreach (string pic in pics) { CreateThumbnail(pic); Console.WriteLine(pic + TID); } Console.WriteLine("Done"); }
Code Summary
As you can see, in CreateThumbnails, we create a string array of image paths. We then iterate over that array, calling CreateThumbnail for each item, as well as writing out the path and the thread id of the executing thread to the console. Lastly, we write out ‘Done’ to the console when complete. The implementation of CreateThumbnail is relatively unimportant to the theme of this post. It uses the Bitmap and Graphics types from the GDI+ libraries to create a thumbnail image (max height / width of 128 PX). If you are interested, you can download the sample code here.
Performance
| Time (in milliseconds) |
| 2274 |
| 2289 |
| 2286 |
Fine Grained Parallelism
The Code
1: private static void CreateThumbnails()
2: {
3: string[] pics = Directory.GetFiles(imageDir, imageExt);
4:
5: var tasks = new Task[pics.Length];
6: for (int i = 0; i < pics.Length; i++)
7: {
8: tasks[i] = Task.Factory.StartNew(state =>
9: {
10: CreateThumbnail((string)state);
11: Console.WriteLine(state + TID);
12: }, pics[i]);
13: }
14: Task.WaitAll(tasks);
15:
16:
17: Console.WriteLine("Done");
18: }
Code Summary
The first thing you might notice is that this code is a bit more involved. If you watch the screencast I did on Channel9 on introducing parallelism into your applications, I describe in more detail how we get to this code from the sequential implementation.
Again, the first thing we do is to create a string array of image paths. The next thing we do (line 5) is to create an array of Tasks (the Task is the type we use to implement fine grained parallelism). We will need this array later. Next we iterate i number of times (once for each path in the array of image paths). Now comes the interesting part. On line 8, we call Task.Factory.StartNew, assigning the result to the appropriate item in the Task array. StartNew is a helper method that is analogous to creating a Task and then calling Start. In code terms, it is similar to doing the following, yet a bit more efficient:
tasks[i] = new Task(state => { CreateThumbnail((string)state); Console.WriteLine(state + TID); }, pics[i]); tasks[i].Start();
You will notice that we are using an overload of StartNew where we explicitly pass the state into the Task using the state object (pics[i] is passed in line 12). This allows us to ensure that the Task is, in fact, working on the image path that we intended it to. If you are new to this, that may sound confusing. Let’s re-write the code for a moment to illustrate what may happen if we didn’t use the state object (or a proper closure):
string[] pics = Directory.GetFiles(imageDir, imageExt); foreach (string pic in pics) { Task t = Task.Factory.StartNew(() => CreateThumbnail(pic)); Console.WriteLine(pic + TID); }
At first glance, this code doesn’t appear to have any issues. However, to quote Inigo Montoya from The Princess Bride “I do not think it means what you think it means”. In this example, the pic variable is not captured correctly in the closure. What this ultimately means is that by the time the Task wakes up and begins calling CreateThumbnail on the pic variable, the pic variable may no longer have the original value from the outer loop.
Getting back to the proper implementation, you will notice that in lines 10 and 11 both CreateThumbnail and the Console.WriteLine call are operating on the state object. The last thing to point out is the call to Task.WaitAll in line 14. As you can see, we pass the Task array we created in line 5 and assigned to in line 8. This call will ensure that all of the Tasks will complete prior to the call to write ‘Done’ to the console.
Performance
| Time (in milliseconds) |
| 1486 |
| 1485 |
| 1510 |
As you can clearly see, this is a dramatic performance increase. This is due to the fact that we were able to distribute the work across the 2 cores on my machine, instead of just one like the sequential implementation. However, the code was a bit involved. Let’s take a look at a couple of other options that provide a higher level of abstraction.
Structured Parallelism
The Code
1: private static void CreateThumbnails()
2: {
3: string[] pics = Directory.GetFiles(imageDir, imageExt);
4:
5: //foreach (string pic in pics)
6: Parallel.ForEach(pics, pic =>
7: {
8: CreateThumbnail(pic);
9:
10: Console.WriteLine(pic + TID);
11: });
12:
13: Console.WriteLine("Done");
14: }
Code Summary
The first thing you will notice is that this code is much simpler. In fact, it is semantically similar to the sequential implementation. Line 5 contains the original foreach construct that I commented out. I replaced it with a call to Parallel.ForEach in line 6. Notice how similar they are.
The ForEach method takes the IEnumerable you want to iterate over as its first argument and a delegate as the second. The Action delegate gets run for each iteration of the loop. In our case, we pass a lamda that calls CreateThumbnail and Console.WriteLine.
Performance
| Time (in milliseconds) |
| 1596 |
| 1534 |
| 1497 |
Here we see similar performance increases over the sequential solution.
PLINQ
LINQ Code
1: private static void CreateThumbnails()
2: {
3: string[] pics = Directory.GetFiles(imageDir, imageExt);
4:
5: var output = pics.Select(pic =>
6: {
7: CreateThumbnail(pic);
8: return pic + TID;
9: });
10:
11: foreach (var line in output) Console.WriteLine(line);
12:
13:
14: Console.WriteLine("Done");
15: }
PLINQ Code
1: private static void CreateThumbnails()
2: {
3: string[] pics = Directory.GetFiles(imageDir, imageExt);
4:
5: var output = pics.AsParallel().Select(pic =>
6: {
7: CreateThumbnail(pic);
8: return pic + TID;
9: });
10:
11: foreach (var line in output) Console.WriteLine(line);
12:
13:
14: Console.WriteLine("Done");
15: }
Code Summary
Think back to when you were a kid. Remember the game where you were shown 2 pictures and you were tasked with identifying the differences between them. In that spirit, the only difference between the LINQ and PLINQ code is the call to ‘AsParallel’. By simply adding the call to this extension method, you have introduced parallelism into your solution (see description above).
Performance
| LINQ | PLINQ |
| 2181 | 1683 |
| 2180 | 1533 |
| 2240 | 1550 |
Sample Code
Acknowledgements
I would like to thanks Steven Toub, Rick Brewster, Huseyin Yildiz, Chris Dern and Aaran Layman for their help answering my questions and offering guidance. Further, it should be noted that this sample was inspired by and was based upon Daniel Moth’s PDC 2008 talk.
Summary
As you can see, there are various approaches to introducing parallelism into your applications, each with their own pros and cons. Some provide greater control (Fine-Grained), while others provide a simpler model (Structured, PLINQ). Hopefully one of them will meet your needs and allow your application to take advantage of the hardware it is running on.
Taking My Medicine
I woke up this morning from a terrible dream. A dream where I had punted a presentation in front of all of my peers. Laying there in bed, I started thinking to myself ‘how could I punt a presentation? I’ve done hundreds of presentations in front of tens of thousands of people. It must have been a dream’. Or was it? I crawled out of bed, walked across the hall into the office and cracked open my laptop. Much to my dismay, when I looked down, there it was. The residue from a single tear. Not just any tear. The presenters tear. The purest of all tears. A tear that can only be shed after punting a presentation in front of one’s peers.
Here is my story…
The Situation
I was at a team offsite that was being held at the Hard Rock Hotel in San Diego. Prior to the trip, my boss sent along a note to all evangelists asking them to be prepared to do a 5 minute presentation to the team. So, who was the team? Along with me were all of my peers, my boss and his peers, his boss and, yes, his bosses boss – or as I call him, my great-grandboss. The general feel you should be getting here is that there were more than a few people in the room who could fire me. Oddly, I still can’t decide who it’s worse to punt a presentation in front of: a) senior management or b) a room full of evangelists who are going to make your life miserable for the foreseeable future. I suppose time will tell.
I digress. The note from my boss actually read that we should be prepared to do a 5 minute presentation on a topic that we are passionate about. I decided upon .NET RIA Services. I should be clear here that I am not new to .NET RIA Services. In fact, it is now sitting on top on ADO.NET Data Services which I am very familiar with and ADO.NET Data Services sits on top of WCF REST with which I am intimately familiar. I should also note that I have presented on .NET RIA Services dozens of times and wrote ALL of the code that I was going to present. Lastly, I should mention that I am not the type of guy to “wing it”. I spent a good deal of time preparing for this, ensuring that I could get my message across in 5 minutes (not an easy task, by the way). In other words, I was ready for success.
The presentations were split across 2 days. 7 or so of my peers went on day 1. Each one made himself and the team proud. There may have been a minor glitch or 2, but they were minor – nothing like what was about to occur on day 2. Anyway, at the end of the day 1 presentations, our GM stood up, thanked all of the presenters and then said those fateful words… something to the effect of ‘you might consider adding a little flair to your demos’. As my friend Jason Mauer would say – enter ominous music here.
The Mistake
There are certain rules that you should never break. I’m not talking about wimpy rules like don’t go swimming for a half hour after you eat. I’m talking about rules which, if you break, there will be epic consequences. Think Bobby Brady and “mom always said don’t play ball in the house” or Maverick and “never leave your wingman”. Well there are a few of those for presenters. One such rule is “never change your presentation just before your present it”. Hi, I’m Rob and I broke that rule.
I wanted to add a bit of flair to my demo. What I did was to add a simple animation to my XAML. I wanted to make a DataForm spin in a circle (using perspective 3D) every time a different record was selected in the DataGrid. It seemed harmless enough. All in all, it was 9 lines of XAML and 4 lines of code. The change was so insignificant, I thought “what could go wrong?”.
The Demo
Things started out ok. I felt relaxed and was ready to go. I started out explaining the context for the presentation. I got into the demo and added the DomainService (if you are not familiar with .NET RIA Services or some of the other technical mumbo-jumbo I discuss a bit later, it is not really necessary to get the rest of this story – however, I do suggest looking into it). The next part of the demo was to add a DomainDataSource control into the XAML – the same XAML I added to animation to. Unfortunately, I opened up the wrong XAML file. Had I not made the “simple change” and added the animation, I would likely have noticed that I opened the wrong page – but I did… I did make that change. It is kind of hard to describe what happened next. I suppose the best way to describe it is I had a mental blue screen. My entire memory dumped. Things started getting all slow. That is, everything but the 5 minute countdown timer. I think it actually sped up.
I did finally figure out that I had opened the wrong page, so I closed it and opened the proper page. However, somehow, the effect of those extra 9 little lines of XAML on my now weakened intellect were devastating. That page (that I had authored myself less than a week ago) could have just as easily been Beowolf. At this point, I knew I was hosed. The timer was at less than a minute and I was flailing. Unfortunately, only thing came to my mind and it went out unfiltered to the audience. If I know my colleagues (and I do), I am sure that this will live on for a long, long time. I looked up at the audience, nodded slowly and said “this is kinda like watching your dad get beat up, isn’t it?”. I’ll leave the audience’s response to your imagination. However, I will tell you that I am almost certain that, as I was walking back to my seat, I could hear playing on the Hard Rock background music from the hall “ha ha ha ha ha ha ha ha, wipeout”.
The Medicine
I named this post ‘Taking My Medicine’. Part of that medicine is sharing that horrifying moment with you, in the hope that you will not repeat it. However, there is a second dose of medicine. At the very end of my presentation (from here on out I’ll just refer to it as ‘the incident’), I told the audience that I would record the presentation properly. I thought I’d share it with all of you, as well. Click here to watch my screencast of .NET RIA Services in 5 Minutes.
The Summary
- Never leave your wingman
- Don’t play ball in the house.
- Never change your presentation just before you present.
Working with Azure Table Storage from PHP
Introduction
Windows Azure Table Storage is a non-relational structured storage system in the cloud that offers massive scalability, durability and high availability. The service is exposed with a RESTful API. As such, it is easily consumable from a variety of platforms, including PHP. In this post, I will illustrate how to consume Azure Table Storage via the RESTful API. It is important to note that on July 31, 2009 we will reach Milestone 2 on the PHP SDK for Windows Azure. Milestone 2 focuses on support for Azure Table Storage. Accordingly, in all of the code you see in this blog post and the accompanying screencasts (Part I and Part II) illustrate accessing Azure Table Storage the “hard way”. Much of the work I had to do by hand in the accompanying example here will be taken care of for you by the SDK. That said, let’s dig in…
PHP Interop Series
This is part of a small series of blog posts and screencasts that I am doing on interoperability between PHP and the Microsoft stack. My goal is to illustrate some features of the MS stack that PHP developers can take advantage of, as well as to illustrate how it is done.
Watch the Screencasts
I have created 2 screencasts that accompany this blog post that you can watch. You can view them here:
- Working with Azure Table Storage From PHP – Part I
- Working with Azure Table Storage From PHP – Part II
What is Windows Azure Table Storage
As stated in the intro, Windows Azure Table Storage is a non-relational structured storage system in the cloud that offers massive scalability, durability and high availability. While the goal of this post is not to dig deep into what Azure Table Storage is, I think it is best to at least provide a high-level overview of what it is and why you should care. Looking at the first sentence in this paragraph, there are 4 major points that need to be covered: 1) non-relational storage system, 2) in the cloud, 3) massive scalability and 4) durability, high availability.
Non-Relational Structured Storage System
It is important to note that while we refer to this storage abstraction as tables, they do not conform to tables in the traditional sense. To start with, the container for tables is not a database, rather a Storage Account. You establish this storage account in the Azure Services Developer Portal (see this blog post for full details). The Storage Account acts as the parent namespace for Table Storage, therefore you will not have any naming collisions with others that have similarly named tables.
A second major difference is that Azure tables do not conform to the traditional rows and columns structure. Azure tables contain entities. I think of entities as property bags. These entities contain 3 or more properties which are typed name-value pairs. I say 3 or more properties because every entity in Azure Tables must contain a PartitionKey, a RowKey and a TimeStamp property (I will go into a bit more detail on the role of these properties later in this post). An interesting byproduct of this design is that tables are completely schema-less. For instance, you are not precluded from adding 2 entities into the same table that have completely different schemas. I do not want to address the inevitable debate that surfaces whenever this statement comes up, but suffice it to say that it is up to the developer to protect the schema in their tables. The figure below illustrates how it is structured.
A third major difference is that there are no relational capabilities in Windows Azure Tables. Many people look at these differences (between this structured storage system and a traditional RDBMS system) and focus on what is missing. The simple reality is that Azure Table Storage is what it is… which is a structured storage system that provides massive scalability.
In the Cloud
Windows Azure is a cloud platform. The data in Windows Azure Table Storage is stored in Microsoft Data Centers around the world and are accessible via HTTP.
Massive Scalability
The typical means of scaling databases is to scale up – buy bigger and bigger boxes. However, after a while you run out of either bigger boxes or money. At that point you have to scale out. In the database world, this process is know as horizontal partitioning or sharding. In RDBMS tables, this means that differing rows of data are stored on different physical partitions. For example, I might store a subset of customers and their orders on one partition and another subset on another (perhaps customers with last names A-M on one and N-Z on another – or perhaps customers in Europe on one, customers in Asia on another …).
You might correctly infer that the more flexible you are in your ability to move data from one partition to another, the more scalability your system will have. For instance, at one extreme, if all of your data must be on the same partition, you can only scale up (not out) and when you reach that threshold, you can scale no more. At the other extreme, if you are able to store each record / entity on a differing partition, you have infinite scalability. Now don’t go getting excited. When data is stored across different partitions, it is quite costly to query it. You are forced to query each partition independently. As a result, you need to take special care to ensure that data that you want to query together remains on the same partition, while still allowing for the scalability required.
As mentioned earlier, every entity in an Azure Table is required to have a PartitionKey property. This PartitionKey provides you with the control to determine which records must be stored on the same partition. Windows Azure is free to move Entities with different PartitionKeys to differing nodes when it needs to, for scaling or load balancing purposes. If you think about it, that is pretty cool. You don’t have to worry about moving the data about. Azure will handle that for you. However, you do need to realize that if you query data across PartionKeys, it will be rather expensive. It is the classic give-take.
Durability, High Availability
Data in Windows Azure is replicated at least 3 times. Further, as described above, Windows Azure will move data about for load balancing purposes (as well as for scaling).
The REST API
I published a blog post a month or so ago that described ad nauseum the REST API for Windows Azure Table Storage. I would urge you to take a look at that post, or at least watch the first screencast that accompanies this post. The understanding of the REST API, as well as the message signing process was key to me to be able to put together the following code.
Writing the PHP Implementation
Caveat (again)
I realize I have stated this before, but I want to mention again that on July 31, 2009, we will be releasing Milestone 2 of the PHP SDK for Windows Azure. This milestone will include code to greatly ease the process of working with Azure Table Storage. Much of the following code will be unnecessary. That said, I think it is very cool to illustrate accessing Table Storage from PHP without the SDK. It illustrates the benefits of exposing an open RESTful API.
Wine.php
In my code, I want to work with classes. To that end, I first created a Wine class as seen here:
<?php class Wine { public $ShortWineName = ""; public $WineLabelUrl = ""; public $BottlePrice = 0.00; public $Description = ""; public $Vintage = ""; public $WineID = 0; public $PartitionKey = ""; public $RowKey = ""; public $TimeStamp; public function __construct() { } } ?>
PHPTableStorageHelper.php
This class is a little helper I wrote. It performs the following functions: 1) Calculates the appropriate URI for my Table (and page) 2) Signs the message, 3) Creates the HTTP Headers for the Request (including the Authorization header containing the signed message, 4) Issues the Request using CURL, 5) Parses the Response HTTP Headers and 6) Returns the Reponse Body.
GetResponse Method Signature
public static function GetResponse($account_name, $shared_key, $table_name, $pageSize, &$nextPartition, &$nextRow){ //Get the base uri $service_uri = self::getUri($account_name, $table_name); //Limit the results by the pageSize $query = ''; if ($pageSize > 0) $query = '?$top='.$pageSize; //Add a filter for paging (if the partition and row were passed if (strlen($nextPartition) > 0 && strlen($nextRow) > 0) { //See if we have already created a query if (strlen($query) > 0) $query .= '&'; else $query .= '?'; //Add the NextPartitionKey and NextRowKey QueryString parameters $query .= 'NextPartitionKey'.'='.rawurlencode($nextPartition); $query .= '&NextRowKey'.'='.rawurlencode($nextRow); } $service_uri .= $query; //Get the date (GMT) $date = self::GetGMTDate(); //Get the signature $signed_message = self::GetSignature($date, $account_name, $table_name, $shared_key); //Get the http headers array $headers = self::GetHttpHeaders($date, $signed_message); $session = curl_init($service_uri); curl_setopt($session, CURLOPT_HEADER, 1); curl_setopt($session, CURLOPT_HTTPHEADER, $headers); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($session) or die('Curl error: ' . curl_error($session)); //Split the response into headers and the actual response body list( $outheaders, $body )= explode( "\r\n\r\n", $response, 2 ); //Split the outheaders into an array and set the ref arguments $outheadersArray = self::http_parse_headers($outheaders); if (array_key_exists('x-ms-continuation-NextPartitionKey', $outheadersArray)) $nextPartition = $outheadersArray['x-ms-continuation-NextPartitionKey']; else $nextPartition = ""; if (array_key_exists('x-ms-continuation-NextRowKey', $outheadersArray)) $nextRow = $outheadersArray['x-ms-continuation-NextRowKey']; else $nextRow = ""; curl_close($session); return $body; }
The core of this helper class is the GetResponse method. This method takes in the account name containing the table to query, the table name, the shared key for use in signing the method and some arguments used for paging. I realize that this method doesn’t allow you to really query a table, rather just return pages of records, but that is ok for the purposes of this post.
Calculate the appropriate URI
The class declares a constant used as a template for the URI to our table. It is as follows:
const uriTemplate = "http://%s.table.core.windows.net/%s";
The first placeholder (%s) in the template is replaced with the account name, while the second is replaced with the table. The first line of code in the method simply does this replacement:
$service_uri = self::getUri($account_name, $table_name);
The next bit of code simply adds a few querystring parameters for paging:
//Limit the results by the pageSize $query = ''; if ($pageSize > 0) $query = '?$top='.$pageSize; //Add a filter for paging (if the partition and row were passed if (strlen($nextPartition) > 0 && strlen($nextRow) > 0) { //See if we have already created a query if (strlen($query) > 0) $query .= '&'; else $query .= '?'; //Add the NextPartitionKey and NextRowKey QueryString parameters $query .= 'NextPartitionKey'.'='.rawurlencode($nextPartition); $query .= '&NextRowKey'.'='.rawurlencode($nextRow); } $service_uri .= $query;
Sign the message
The next 2 lines of code get the signed message that is to be used for the Authorization HTTP header.
//Get the date (GMT) $date = self::GetGMTDate(); //Get the signature $signed_message = self::GetSignature($date, $account_name, $table_name, $shared_key);
Firstly, we get the current date in GMT format. Next we call a helper method that creates a string to sign and signs it with the private key. Here is that helper method:
public static function GetSignature($date, $account_name, $table_name, $key){ $message_to_sign = "$date\n/$account_name/$table_name"; $signed_message = base64_encode(hash_hmac('sha256', $message_to_sign, base64_decode($key),true)); return "SharedKeyLite $account_name:".$signed_message; }
Create the HTTP Headers
The next line after returning the signature simply calls a helper method to return an array containing the HTTP headers:
//Get the http headers array $headers = self::GetHttpHeaders($date, $signed_message);
Here is the helper method:
public static function GetHttpHeaders($date, $signed_message){ return array("x-ms-date:$date", "Authorization:$signed_message", "Accept:application/atom+xml, application/xml"); }
Issue the Request
The next few lines use CURL to issue the HTTP GET Request to the URI we calculated, passing the HTTP headers
$session = curl_init($service_uri); curl_setopt($session, CURLOPT_HEADER, 1); curl_setopt($session, CURLOPT_HTTPHEADER, $headers); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($session) or die('Curl error: ' . curl_error($session));
Parse the Response HTTP Headers
The next few lines parse the HTTP Headers from the response. CURL doesn’t give you access to an array of headers. You have to do this yourself. We have to in order to parse out the continuation headers that are returned. These provide a pointer to us for paging. Remember earlier when we added the querystring parameters? We used the values passed here from a previous Response.
//Split the response into headers and the actual response body list( $outheaders, $body )= explode( "\r\n\r\n", $response, 2 ); //Split the outheaders into an array and set the ref arguments $outheadersArray = self::http_parse_headers($outheaders); if (array_key_exists('x-ms-continuation-NextPartitionKey', $outheadersArray)) $nextPartition = $outheadersArray['x-ms-continuation-NextPartitionKey']; else $nextPartition = ""; if (array_key_exists('x-ms-continuation-NextRowKey', $outheadersArray)) $nextRow = $outheadersArray['x-ms-continuation-NextRowKey']; else $nextRow = "";
Here is the helper method http_parse_headers:
static function http_parse_headers($headers=false){ if($headers === false){ return false; } $headers = str_replace("\r", "", $headers); $headers = explode("\n",$headers); foreach($headers as $value){ $header = explode(": ", $value); if(count($header) == 1){ $headerdata['status'] = $header[0]; } elseif($header[0] && $header[1]){ $headerdata[$header[0]] = $header[1]; } } return $headerdata; }
Return the Response Body
The last 2 lines simply clean up and return the response body.
curl_close($session);
return $body;
WineContext.php
This class calls our helper class above, parses the ATOM Formatted response and returns a collection of the Wine class. I’m not going to go into any detail, as it is pretty straightforward:
public static function GetWinePage($table_name, $pageSize, &$nextPartition, &$nextRow) { include_once('config.php'); $wines = array(); $response = PHPTableStorageHelper::GetResponse($accountName, $sharedKey, $table_name, $pageSize, $nextPartition, $nextRow); //Load the xml into simplexml and register the namespaces //referenced in the xml $dom = new SimpleXMLElement($response); //Create vars for the namespaces. //Calls to children takes the namespace (if exists) $metadataNS = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"; $dataservicesNS = "http://schemas.microsoft.com/ado/2007/08/dataservices"; //Iterate over the entity nodes foreach($dom->entry as $entry) { //Get a reference to the properties node $properties = $entry->content->children($metadataNS)->children($dataservicesNS); //Create the wine $wine = new Wine(); $wine->WineID = (int)($properties->WineID); $wine->ShortWineName = (string)($properties->ShortWineName); $wine->Description = (string)($properties->Description); $wine->BottlePrice = (float)($properties->BottlePrice); $wine->Vintage = (string)($properties->Vintage); $wine->WineLabelUrl =(string)($properties->WineLabelUrl); //Add the wine to the array $wines[] = $wine; } return $wines; }
Catalog.php
Now on to consuming our classes. I’m not going to get into all of the paging logic and UI code. At the end of this post is a link where you can download all of the files. The paging code should be pretty self-explanatory. I do want to show you the code that calls our context and writes the HTML, though. Firstly, I included the context and the wine classes:
<?php include('Wine.php'); include('WineContext.php'); ?>
Next, at the appropriate place in the HTML, I call our context and return the array of wines. I then iterate over the results, outputting the appropriate HTML.
<?php //Get the data $table_name="Wines"; $wines=CohoStorageData::GetWinePage($table_name,2,$nextPartition,$nextRow); //Add the next row returned from the service to the array $nextRowArray[] =$nextRow; //Iterate over the results foreach ($wines as $wine) { echo'<tr>'; echo '<td>'; echo '<table width="100%" border="0" align="center" cellpadding="8" cellspacing="0" class="thinblueline" style="background-color: White;">'; echo '<tr>'; echo '<td valign="top">'; echo '<img src="'.$wine->WineLabelUrl .'" />'; echo '</td>'; echo '<td valign="top">'; echo '<strong>'; echo $wine->ShortWineName; echo '</strong>'; echo '<br />'; echo '<span>'; echo $wine->Description; echo '</span>'; echo '<br />'; echo '<br />'; echo '</td>'; echo '<td width="80" align="right" valign="top">'; echo '<strong>'; echo '$'.number_format($wine->BottlePrice,2,'.',' '); echo '</strong>'; echo '<br />'; echo '<br />'; echo '<img id="ImageButton1" productid="'.$wine->WineID .'" cssclass="noUnderline" onclick="ItemSelected" src="images/selectbutton.gif" />'; echo '</td>'; echo '</tr>'; echo '</table>'; echo '</td>'; echo'</tr>'; } ?>
Get the code
You can download the code here. Don’t forget to add the appropriate account name and key in config.php. Also, this code has no provisions for creating the tables or adding the records. If you want direction on that, please follow this blog series. It will illustrate how to do it (in .NET not PHP). Otherwise, you can wait until July 31 (or shortly thereafter) and I will illustrate these features in the SDK for PHP.
Hosting a PHP Application in Windows Azure
Introduction
At MIX ‘09 we (Microsoft) announced support for FastCGI in Windows Azure. FastCGI allows us to host applications like PHP both safely and performantly (warning – performantly is not a real word). In this post, I will begin with a very brief overview of what Windows Azure is and why you might consider hosting your PHP apps on Windows Azure. I will then provide you with a couple of resources that you can use to easily publish your PHP application to Windows Azure, including a link to a screencast I created that illustrates just how to publish a PHP application to Windows Azure.
PHP Interop Series
This is part of a small series of blog posts and screencasts that I am doing on interoperability between PHP and the Microsoft stack. My goal is to illustrate some features of the MS stack that PHP developers can take advantage of, as well as to illustrate how it is done.
What is Windows Azure (from 30,000 feet)
Simply put, Windows Azure is a cloud platform. The platform provides the ability to host applications (Web Applications, Web Services and Services that don’t accept HTTP Requests) and to store and retrieve data in the cloud. The important part of the last sentence is “in the cloud”. Clearly, Windows Server 2008 (along with a multitude of other operating systems) provides the services to host applications and store and retrieve data. The “in the cloud” part is the clear differentiator for Windows Azure.
You might then think that the cloud to Microsoft would simply be one or several datacenters filled with servers running Windows Server 2008 either virtually or on physical servers. However, it is much more than that. What differentiates Windows Azure from that environment is something known as the Windows Azure fabric. This fabric ties all of the Azure nodes together into a cohesive whole. This fabric provides several benefits to the applications running in Windows Azure, including manageability and health monitoring.
Windows Azure provides a portal where the application owner can simply configure how many instances of an application are running in the cloud. In the case of web applications running on multiple instances, you need not worry about configuring the load balancer. The Windows Azure fabric handles that for you. For example, if you decide that you want your application running on 5 instances instead of 2, you simply change a single setting in a configuration file. Windows Azure does the rest. You application is deployed on 3 additional instances that are wired appropriately to the load balancer.
What happens when one of these instances is no longer healthy? Another of the functions of the fabric is to monitor the health of the applications and servers. Windows Azure will simply bring up another instance of your application and re-route traffic to that new, healthy instance. Think of the complexity of building this kind of tolerance yourself.
Why Host my PHP Application in Azure?
Some of the benefits of hosting your application in Azure should be apparent from the preceding discussion. They include scalability, availability and manageability. Other benefits that may not be so apparent are the fact that you only pay for what you use and there is no lead-time required to bring up instances of your applications.
Pay for what you use / Lead time required
A key differentiator between all cloud platforms (not just ours) and hosted environments is that with cloud platforms you only pay for what you use and do not have to commit to future use. In a typical hosted environment, you will likely have to commit to a defined term of use. Further, in hosted environments, there is often a lead time required to get up and running. There are obviously exceptions to this, notably in shared hosting scenarios. However, if you are looking for dedicated hosting on a number of nodes, you will probably find that a significant lead time is required, along with a long-term contract.
With Windows Azure, you simply pay for what you use and the only lead-time that is required is the amount of time required to spin up the new node. This provides you with the flexibility to spin up new instances when demand requires and scaling back when that action is warranted.
Scalability and Availability
This pay for what you use model allows you to scale up when demand requires and scale back when demand is down. This can be great for startups that are intellectual property rich and cash poor. They do not want to invest heavily in the infrastructure required to meet their forecasted demand. However, they do want to be able to meet demand if their product or service takes off. Further, because the Windows Azure fabric is monitoring the health of your application instances, re-routing requests to new instances where required, you can be self-assured that your application will be available to your customers.
Manageability
The goal of any abstraction layer is to hide the complexity of a given task from the end user, allowing them to focus on business-specific problems. By hosting your PHP application in Windows Azure, you need not worry about provisioning servers, configuring the operating systems, administering patches, deploying instances of web applications and wiring them to load balancers. All of this is neatly handled for you. All you have to do is simply deploy your application to the Azure portal and change some simple configuration settings.
Resources for Publishing your PHP Application to Azure
The following are some resources that you can take advantage of. They make it easy to publish your PHP application to Windows Azure. They include a screencast I put together that details every step, a comprehensive blog post by Wade Wegner that lists the steps for publishing (this is what I used when I first did it), along with a link to a blog post I put together that illustrates how to get started with Azure. The last post shows you all of the steps required to sign up for Windows Azure.
- Screencast on Hosting a PHP Application in Windows Azure
- Wade Wegner’s Post on ‘Running a PHP application on Windows Azure’
- Post on Getting Started with Windows Azure
Comments Please
Please leave me a comment, letting me know whether this post / series is helpful to you or not. I would really appreciate it!
PHP and IIS: Running PHP under Fast CGI and Url Rewriting
Introduction
You can run PHP (as well as other CGI apps) on IIS7 with high performance and reliability thanks to FastCGI. CGI is a protocol that defines how web servers launch an executable resulting from a request, pass it arguments and return the dynamic response. You have been able to host CGI applications in IIS in the past, however there have been challenges prior to FastCGI. As it turns out, the challenge is that there are certain modules (in PHP, for instance) that are not thread safe. For that reason, IIS traditionally spun up a new process for each request. This provided the reliability necessary in the face of non-thread-safe modules. However, the performance suffered due to the cost of spinning up all of these processes. Enter FastCGI. It guarantees that each process will handle 1 request at a time (providing the reliability), but it allows for process reuse by maintaining a pool of processes.
While installing PHP on IIS7 wasn’t overly complex in the past (see this article if you want the details) we now have the Web Platform Installer that makes installing FastCGI, PHP and much much more a breeze. Now, just because you can host PHP on IIS with reliability and high performance, it doesn’t necessarily mean you should. You need some reasons, right? Well, in this post, I will illustrate how to install PHP and FastCGI on IIS7 easily and illustrate one of many reasons you will want to: The UrlRewrite Module. This module allows you to easily create SEO-friendly Uris for your application. Let’s get to it.
PHP Interop Series
This is part of a small series of blog posts and screencasts that I am doing on interoperability between PHP and the Microsoft stack. My goal is to illustrate some features of the MS stack that PHP developers can take advantage of, as well as to illustrate how it is done.
Screencasts
You can see screencasts on YouTube of the topics in this post here:
- Installing PHP and FastCGI on IIS7 in under 5 minutes
- Create SEO-Friendly URLs with the IIS7 UrlRewrite Module
Set Up a Test Environment (optional)
You can test all of this on Vista, Windows 7 or Windows Server 2008. We have made it pretty easy for you to to set up a virtual environment for testing. You can click here to download Windows Server 2008 Evaluation Virtual Hard Drive Images. Although it says Virtual Server 2005 is required, the VHD works on Virtual PC 2007, as well. You simply need to download the WS08_RTM_x86_EnterpriseVHD.exe or, if you want smaller downloads the WS08_RTM_x86_Enterprise.part01.exe and all of the subsequent rar files. You will also need the WS08_ServerCore86_EnterpriseVHD.exe. You simply uncompress these and register the VHD with Virtual PC or Virtual Server. That is exactly what I did.
Install the Web Platform Installer
- Navigate to http://www.microsoft.com/web/downloads/platform.aspx and click the download link to ‘Microsoft Web Platform Installer 2.0 Beta’
- Click Run (If you get a security warning, click run again)
- The Web Platform Installer is now installed. You will see the UI, where you can choose items to install. Feel free to close this. You can re-open it at any time.
Install PHP, FastCGI and the URLRewrite Module
- Open the Web Platform Installer 2 Beta (if you closed it)
- Under ‘Web Platform’, choose ‘Web Server’. Select the following items to install
- Static Content
- URL Rewrite
- CGI
- Under ‘Web Platform’, Choose ‘Frameworks and Runtimes’. Select the following item to install
- PHP 5.2.9-2
- Click ‘Install’
- Click ‘I Accept’ if you accept the license terms and conditions
- That is it! PHP is installed and FastCGI is configured for you.
Test a PHP Sample Application
I have a very simple PHP application that you can use to test your install (as well as the rewrites later). You can download it here. If you have your own application feel free to use it. Here are the steps I used to setup my test environment on my Windows Server 2008 VHD:
- Create a directory called Demos
- Download the sample application from the link above
- Copied the TestPHP directory under my new demos directory. (if you cannot seem to copy in your virtual hard disk, make sure you may need to install the virtual pc additions)
- Register the virtual directory in IIS
- Open IIS
- Right-Click on your web and choose Add Virtual Directory
- Set the Alias to ‘TestPHP’ and the Path to C:\Demos\TestPHP
- Open a browser and navigate to: http://localhost/TestPHP/catalog.php. You should see something like this:
To prove to yourself that php is actually running and configured, navigate to http://localhost/TestPHP/contactus.php. Take a look at the code and you will see the line of code that adds the header ‘Contact Us’:
<?php echo "Contact Us" ?>
You can also navigate to http://localhost/TestPHP/index.php. It will echo the results of phpinfo().
Add some UrlRewrite Rules
Remember that we have already installed the UrlRewrite 1.1 Module with the Web Platform Installer. Let’s use this module so we can create some friendly URLs for our PHP Application. We do this by adding rewrite rules. I’m going to show you a feature that is new to version 1.1 called Rewrite Maps. It acts just like it sounds. It allows you to define simple rewrite maps (your basic from –> to mapping). I would guess that this will be used pretty commonly when creating search-engine-friendly URLs. Let’s take a look.
- Open up IIS and click on your default web site. Then double-click on Url Rewrite
- Now we want to create our map. Click on the ‘View Rewrite Maps…’ link on the right side.
- Click ‘Add Rewrite Map…’
- Click ‘Add Mapping Entry…’
- Remembering that Virtual Directory name was ‘TestPHP’ and our catalog page was called ‘catalog.php’. The URL to our page is: http://localhost/TestPHP/catalog.php. We also had a page called ‘contactus.php’ (Url http://localhost/TestPHP/contactus.php). These are pretty ugly Urls. The extension ‘php’ means nothing to the general public. Perhaps we want the Urls to look more like http://localhost/catalog and http://localhost/contact. Let’s add the following 2 rules:
- Now we need to add the rewrite rule that uses the map. Click ‘Add Rules…’
- Choose ‘Rule with rewrite map’
- Leave the rule action set to ‘Rewrite’. Under the ‘Choose the rewrite map’ section, choose the map you created earlier. Mine was named ‘PHPTestMap’. Click ‘OK’
Test It
Now we can type in our friendly URI into the address bar of our browser. Nice.
Conclusion
As you can see, the Web Platform Installer makes configuring PHP to run on IIS a simple task. You can also see the power of the IIS pipeline. There are a wide array of modules like the UrlRewrite module that you can take advantage of.
Azure Application Part 3: Expose (REST) Web Service And Consume in Silverlight
This is part 3 in this series where I am building an Azure shopping cart application from the ground up. In this post, I will create a RESTful service using WCF and host it in Windows Azure. This service will source it’s data from Azure Table Storage. I will then illustrate how to consume this service from a Silverlight component hosted in Windows Azure. Giddyup.
(In part 2 I illustrated how to set up and access Azure Table Storage in both the development environment, as well as in the cloud. I created a Wine table, added a few entities and retrieved them both locally and from the cloud. I did all this taking advantage of the ADO.NET Data Services .NET Client Library and the StorageClient sample application.)
Watch the Screencast
Building Our RESTful Service
By now, you have more than likely heard of REST and have at least an ancillary understanding of it. I further hope you have had the chance to develop RESTful services, taking advantage of our webHttpBinding in WCF. If not, I invite you to look at my 10 part series on REST in WCF. In that series, I provide an overview of REST and illustrate how to implement RESTful services using WCF 3.5. The goal of this post is not to do a deep dive on REST, rather, to illustrate that you can host these WCF RESTful services in Windows Azure (as well as consume them from components hosted in and out of Windows Azure). That being said, if you are not familiar, I will provide a 50,000 foot description of what REST is. (please forgive me, but I am copying this description almost verbatim from an earlier post of mine)
REST Overview
REST is an architectural style that embraces the standards of the web such as HTTP and URI. Because it is an “architectural style” there are endless debates as to what is RESTful and just what REST means. I only intend to provide a general overview of REST here, as addressing that debate is beyond the scope of this post. However, if you are interested in an in-depth understanding of REST, please read/view my 10+ part series of posts and screencasts on the subject.
In general, exposing services using a RESTful architectural style simply means embracing and adhering to the standards of the web. What the heck does that mean? Here are some examples:
- Treat everything as a resource and use URIs to uniquely identify resources. My customers may be represented as http://www.robbagby.com/customers, whereas a single customer named fred may be represented as http://www.robbagby.com/customers/fred. Finally my customers that have not paid may be represented as http://www.robbagby.com/deadbeatcustomers.
- Use the appropriate HTTP Verbs (GET, PUT, POST, DELETE) for the appropriate action. Issue an HTTP GET to http://www.robbagby.com/customers/fred fetch a representation of fred, whereas issue an HTTP DELETE to the same URI to perform a delete action.
- Where appropriate, use standard representation formats (ATOM, XHTML, Microformats, etc.) to represent resources.
- Use HTTP Headers appropriately
- Use HTTP Status Codes to alert the caller as to the result of the call.
- The Accept HTTP Header can be used to alert the server to the representation format you would prefer.
- Use the Authorization header for authorization credentials.
The above list is certainly not an exhaustive list, but should give you a general idea of what REST is (with regards to services).
Why Build a RESTful Service
For the purposes of this post, we are going to create a simple GET service that simply exposes the Wines that we are storing in Azure Table Storage. Why are we going to do that? Azure Table Storage data is already exposed RESTfully, isn’t it? Well there are a few reasons. They are as follows:
- Perhaps we want to expose our wines without requiring authentication.
- Perhaps we want to expose our wines in a different representation format than ATOM (such as JSON or POX or whatever we feel like)
- Perhaps we want to massage the data prior to exposing it.
- Perhaps this data was not sourced in Azure Table Storage. Perhaps this data was stored in SDS.
- We want to consume this data from Silverlight. Silverlight precluded you from adding an Authentication header when making a request. Therefore, as of now, you cannot directly access Azure Table Storage via Silverlight.
- This is a sample, so I want to keep this part simple. I do not want to overcomplicate the sample with a bunch of data manipulation.
- Implement Our RESTful Service
There are many ways to skin a cat (I just learned last night that this saying has nothing to do with felines, rather Catfish – go figure). What I mean is that there are multiple ways to create a REST service with WCF. There are 2 out-of-the-box templates and a bunch more in the WCF REST Starter Kit on CodePlex. I am going to use the AJAX template (and de-AJAXify it) because it take a few steps and renders very clean code. For production applications, I would strongly urge you to take a look at the WCF REST Starter Kit. Enough babbling, here are the steps to create the service:
- Right-Click on the AzureStore_WebRole project > Add > New Item
- Choose the ‘AJAX-enabled WCF Service template and Name it: WineService.svc
- The template did a few things for us:
- It added references for us, including System.ServiceModel
- It added a System.ServiceModel element in the web.config (if there wasn’t on, which in our example there wasn’t). Under this node, it added the appropriate WCF Configurations, including an endpoint with our RESTful binding webHttpBinding and a pointer to an enableWebScript endpoint behavior (the AJAXiness of this template).
- It added an svc file. This file acts as the endpoint when hosting in IIS or WAS. The file has a ServiceHost directive, pointing to the type that contains the service code, among other things as we’ll see in a minute
- It added a class file that contains the implementation. The ServiceHost above points both to the physical location of this class (CodeBehind), as well as the type (Service). This class is where we are going to do our work.
- Open the web.config and delete the System.ServiceModel section of the configuration (from <System.ServiceModel>… to </System.ServiceModel>). This template used a configuration approach. We are going to go with a configurationless model. We do this by declaring a Factory in the ServiceHost directive in the svc file.
- Open up the svc file (right-click on the svc file > View Markup).
- Add Factory=”System.ServiceModel.Activation.WebServiceHostFactory” to the ServiceHost directive. This is the configurationless model. This factory will dynamically set up an instance of the WebServiceHost in response to requests. It will set up a default endpoint, if appropriate, with the binding set to webHttpBinding, our REST-Friendly binding.
- So, now we are all set up from a configuration(less) poing of view. Now we just need to write the service for the code.
- That’s it. We are ready to test.
- Run your project (F5) (remember that we are still pointing at Azure Table Storage in the cloud. You might want to change your configuration settings back to point at local developer storage
- Change the URI in Internet Explorer to the following: http://127.0.0.1:81/WineService.svc/wines Here is what you should see:
- Cool, our service is working. We now need to change the ResponseFormat back to Json. Change the ResponseFormat to WebMessageFormat.Xml in WineService.svc.cs.
Create Our Silverlight Component
We are going to build a Silverlight component that will consume the RESTful service we just created. In this post, we will start building out the catalog component. If you remember back to the first screencast, this is the portion of the application where the wines were exposed and you were able to page through it. I will implement the paging in a future post. What we are going to do here is to:
- Create a ListBox in Xaml
- Wire up an event handler for the loaded event
- Call our RESTful service
- Deserialize the response to a collection
- Bind our ListBox to the collection
- Pretty Up the Xaml
Well, now that we know what we are going to do, let’s get to doing it:
- Add a Silverlight Application Project to the Solution: Right-Click the Solution > Add > New Project > Silverlight > Silverlight Application
- Leave the defaults on the Add Silverlight Application. These choices will add this project to the Silverlight Applications for our web role, will create 2 test pages that by default contain a control from our project and setup debugging.
- Add a ListBox directly under the grid.
- Wire up a Loaded Event Handler to fetch the Wines
- Open Page.xaml.cs
- Wire up the event handler in the constructor
- Add a private property that returns the root Uri to the web. We will use this to calculate the Uri to our RESTful service
- Code up the event handler for the loaded event. Here we want to call our RESTful service
- Start by using the helper method we created earlier to calc the Uri to our RESTful service
- Create an instance of the WebClient class. This is the simplest HTTP networking class to use in Silverlight.
- We are going to call the OpenReadAsync method to issue an HTTP GET to our RESTful service. The call is asynchronous (as are all networking calls in Silverlight), so we must first wire up an event hander to handle the response.
- Add references to System.ServiceModel.Web and System.Runtime.Serialization. We need these to use the DataContractJsonSerializer to deserialize the response.
- OK, so now we are ready to write the callback method for our HTTP GET to our RESTful service. This is where it may seem a bit tricky. Remember that our service returns a List<Wine>. The challenge we will have is that our Silverlight control has no concept of what a ‘Wine’ is. That class exists on the server, and the control is on the client. So what we need to do is to create a Wine class on the client that we can use to deserialize our response.
- Write the event handler for OpenReadCompleted. We will be passed the response as a Stream in the EventArgs. We will use the DataContractJsonSerializer to deserialize the response. Once deserialized, we can simply set the ItemsSource of the ListBox.
- Test It
- Pretty it up. We got it working, but it isn’t very nice looking.
- Open App.xaml
- Add the Layout Styles and the ListBox Styles
- Open Page.xaml
- Delete the Height and Width attributes from the UserControl node
- Update the layout of the control. Replace the Xaml with the following:
- Add a DataTemplate to the ListBox
- Copy the Images Directory from the Web into the Silverlight Project
- Test It
Well, now we’re getting somewhere! It’s starting to look pretty good. In the next post, I will implement paging, so don’t simply fetch all of the wines, rather we fetch a few at a time. In future posts, I will illustrate how to use SOAP services instead of REST, implement the cart, security, and much, much more. Until then…
Azure Application Part 2: Access Azure Table Storage
This is part 2 in this series where I am building an Azure shopping cart application from the ground up. In this post, I will create a simplified ASP.NET version of the wine catalog. We will create a table in developer storage (the local version of Azure Storage) to store our wines and write 2 web pages: 1 to view all wines and another to add a wine. We will then access the same table in the cloud in Azure Table Storage.
(In part 1 I prepared my environment by setting up my development environment, creating a Windows Azure Account and creating a Hosted Service account. I then created a Web Cloud Service project in Visual Studio and wrote a very simple “Hello, World” example. I ran this sample locally and debugged it. I then deployed it to the cloud.)
Watch The Screencast
Add The 2 ASP.NET Web Pages
Let’s get started by adding the 2 ASP.NET web pages we are going to be working with in this post. We want a page to view all wines (we will work with paging in a subsequent post) and a page to add a wine. I don’t plan on illustrating editing a wine, but if I receive any feedback – hint, hint – I can change my plans.
- Right-Click on the AzureStore_WebRole project > Add > New Item
- Choose Web > Web Form > Name: ViewWines.aspx
- Add a GridView (WineGridView) and a Button (AddWineButton)
- Follow the same process as above to create a web form named AddWine.aspx
- Add the following controls using whatever layout you wish (I know – tables are so 2002. BTW, do you know when it is actually good practice to use tables? When you want a table)
- Download the images folder that contains the wine images from here
- Add the Images folder (and it’s contents) to the AzureStore_WebRole project
We’ll get back to these pages after we have our table set up…
A Brief Overview of Azure Tables
Azure Storage Tables are table-like structured storage. I say table-like because they do not conform to the rows / columns structure we are used to for tables. Azure Tables store Entities which are analogous to a row. Entities are comprised of name-value pairs called Properties. It is important to understand that Azure Tables do not enforce schemas. Therefore, a table can store entities with wholly different structures. However, the developer can choose to enforce schemas via code.
The Storage Account acts as the parent namespace for Table Storage, therefore you will not have any naming collisions with others that have similarly named tables. Here is the best visual I could come up with to illustrate the structure:
You may have noticed that, unlike some other cloud storage systems, the properties are typed. Here is a list of supported types:
- Binary
- Bool
- DateTime
- Double
- GUID
- Int
- Long
- String
There are 3 properties that every entity must have! They are:
- PartitionKey (string) – Tables are partitioned. The goal of Table Storage is to support massive scalability and availability. We therefore load balance across storage nodes. The partition key is used to tell the infrastructure that entities with the same partition key need to be stored together. The partition key forms half of the entities primary key.
- RowKey (string) – The RowKey is other half of the dual key.
- Timestamp (DateTime) – This property is used to store the last modified date and is used for things like optimistic concurrency.
Setting Up For Azure Tables
In a previous post, I discussed ad nauseam the REST API for Azure Table Storage, the role of ADO.NET Data Services, as well as the purpose of the StorageClient application so I am not going to go into much detail here. To summarize that post bullet style in less than 500 words:
- ADO.NET Data Services is a framework that allows one to easily expose and consume data services.
- The framework includes a server library that exposes data securely as RESTful services, as well as client libraries to enable consuming these services easily. One such library is the .NET Client Library.
- The ADO.NET Data Services team implemented a REST API that is compliant with the ADO.NET Services API, with some minor differences (for a listing of those differences, see this documentation).
- One of the notable differences is the Shared Key (Lite) Authentication extension. This is how requests to Azure Table Storage are authenticated.
- The Windows Azure SDK shipped with a StorageClient sample application that extends the .NET Client Library, adding functionality such as signing the requests.
We are going to take advantage of the StorageClient sample application, using it as our API. The nice thing about StorageClient and the .NET Client Library is that they completely abstract away the complexity of making these RESTful calls. They hide the HTTP calls, the serialization and deserialization, as well as the message signing. We just work with objects. Let’s get started coding by creating the object that will represent our entity.
Create The Object That Represents Our Entity
We need to start by creating a class that represents our entity. When fetching an entity from Table Storage, it will be deserialized into this type. We will also use this entity for actions. Let’s get started.
- Add a reference to System.Data.Services.Client
- Set a reference to the StorageClient library. You can either add the sample project to the solution and add a project reference or you can add a reference to the compiled dll. I am going to add the StorageClient project to the solution and add a project reference.
- Add a new class named Wine.cs to the AzureStore_WebRole project
- Add 5 properties to the class.
- string ShortWineName (can be auto-implemented)
- string WineLabelUri (can be auto-implemented)
- string Vintage(can be auto-implemented)
- double BottlePrice (can be auto-implemented)
- int WineID (do not make it auto-implemented)
- Implement class TableStorageEntity from StorageClient.
- You will have to import the Microsoft.Samples.ServiceHosting.StorageClient namespace
- Remember that every entity in Table Storage requires 3 properties: PartitionKey, RowKey and TimeStamp. The TableStorageEntity base class has these properties.
- Every entity in ADO.NET DataServices needs to have a unique key. ADO.NET DataServices uses a DataServiceKeyAttribute to annotate what the unique key is. As pointed out earlier, the PartitionKey and the RowKey form a dual key.
- Add a default constructor (this will be called upon deserialization), as well as a convenience constructor. In the overloaded constructor we can call the base class constructor, passing the PartitionKey and the RowKey. The base constructor simply sets those properties. In this example I am not partitioning wines, so I set the PartitionKey to be the same for all wines. I may address partitioning in a later post.
- If the convenience constructor is called, our entity is set up correctly and can be added to Table Storage. If the default constructor is called, you will note that the PartitionKey is set, but the RowKey is not. EVERY entity in TableStorage requires a PartitionKey, RowKey and TimeStamp. The infrastructure handles the TimeStamp, so we only need to set the other properties. It should now be clear why I didn’t use an auto-implemented property for WineID. We need to set the RowKey in the setter.
- That is it for the Wine Class. Here is the complete code:
Create Our DataServiceContext Class
In a previous post detailing the REST API for Azure Table Storage I discussed the role of the DataServiceContext, as well as what the StorageClient’s TableStorageDataServiceContext class brought to the table. To summarize, the DataServiceContext (part of the ADO.NET Data Services .NET Client Library) maintains state between interactions in order to support features such as identity resolution and optimistic concurrency. The TableStorageDataServiceContext subclasses the DataServiceContext, adding functionality such as digitally signing the requests for authentication purposes. Here we will create our TableStorageDataServiceContext:
- Add a class named CohoContext to the AzureStore_WebRole project
- Implement TableStorageDataServiceContext. You will need to import the Microsoft.Samples.ServiceHosting.StorageClient namespace.
- We now need to add a DataServiceQuery, exposing Wines, to the class. Quoting Mike Flasko and Elisa Flasko from Expose And Consume Data in A Web Services World, “The DataServiceQuery object represents a specific query against the store defined using the URI syntax”.
- That’s it for the DataServiceContext Class
Add Configuration Settings
We need to store the Table Storage configuration settings (our AccountName, our SharedKey used to sign the requests and the TableStorageEndpoint which is the URI to our TableStorage. Remember that we may have multiple instances of our roles, so we store the configuration settings in the cloud service project. Specifically, we add the configuration definitions in a csdef file, with the actual values in a cscfg. Let’s add our settings.
- Open the ServiceDefinition.csdef file from the AzureStore cloud service project.
- Add a ConfigurationSettings node just below the end InputEndpoints.
- Add 3 Settings: AccountName, AccountSharedKey and TableStorageEndpoint
- Open the ServiceConfiguration.cscfg file from the AzureStore cloud service project.
- Add the Settings with the development store values. The development store values are the same for all machines. Here is the full key: Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
- We are done for now. We will update these settings later when we create our Table Storage project in the cloud. For now, we will work with the local development environment.
Create The Tables In The Development Store
The TableStorage class from the StorageClient sample has a static method named CreateTablesFromModel. You pass it your context and your account information for authentication and it will infer a list of tables from every type in the context class that is derived from DataServiceQuery. It will create those tables if they do not exist. However, this does not work for development storage. Not to worry, out friend Visual Studio knows how to do the same thing for us.
If you didn’t know, the developer storage actually uses Sql Server to store the data locally. Visual Studio can infer the list of tables, as well and will create the local tables. Let’s do it:
- Save and build your project
- Right-Click on the cloud service project (AzureStore) and choose ‘Create Test Storage Tables’
- Wait for the confirmation
- (Optional) Open Sql Server Management Studio and look at the new database (AzureStorage) and table (Wine)
That is it. We are ready to write some code, accessing the data. Let’s get to it.
Build A Class To Encapsulate The Data Calls
- Add a class named CohoDB to the AzureStore_WebRole project
- Add GetWines, AddWine and InitializeTables static methods to the class. We will call InitializeTables when working with the cloud storage.
Update Our Web Pages
Now it is time to consume our calls. Let’s start with ViewWines.aspx.
- Update the Page_Load with the following Code
- (Optional) Format the GridView. You can watch the screencast to see how I formatted the grid.
Now let’s update AddWine.aspx
- Wire up an event handler for the SaveButton Click event
- Implement the event handler. Create the wine, call our AddWine method and redirect to the ViewWines.aspx page.
Test It
- Set ViewWines as your start page and run the application (F5)
- No wines exist so the grid will be empty
- Click the AddWines button, add a wine and click Save
- Repeat a few times
Here is what you should see (if you formatted the grid like me):
I fully realize that this is still somewhat ugly. We will fix that in subsequent posts where we convert this to a Silverlight application. The goal of this post was to introduce how to access table storage and make use of it. The only thing we have left to do is to update the application to actually use the cloud and not the developer storage.
Consume Table Storage In The Cloud
This is easier than you might think. If you created a WIndows Azure Account, received your invitation token and redeemed it, all you need to do is to create a Storage Account.
- Open the Azure Services Developer Portal
- Click on Add Project
- Click on Storage Account
- Add a label, description and a name for your account. This name must be globally unique. Here is what you will see after you have created the project
- Open the ServiceConfiguration.cscfg file from the AzureStore cloud service project.
- Update the AccountName setting to the account name you created in step 4
- Update the AccountSharedKey to the Primary Access Key you are given for your account
- Update the TableStorageEndpoint to “http://table.core.windows.net/”. DO NOT INCLUDE THE ACCOUNT NAME IN THIS SETTING. In my case, I might be tempted to set the TableStorageEndpoint setting to “http://bagby.table.core.windows.net”, but THAT WOULD BE WRONG and I will be punished for it.
Once I have made those changes, I can test it again – Sort of. We have to do one small thing. Our Wine table was not created in the cloud. I need to make a call to TableStorage.CreateTablesFromModel in my code. It is good practice to treat this method call similarly to how you treat a CREATE DATABASE call in traditional applications. Many examples you will see will look like what you see below with the call in a Get or some other action.
While this works, it is inefficient. I will keep it for this example, as I <insert some semi-valid excuse to hide the fact that I am lazy and this is the end of a long post>.
Now we can access our data in the cloud. After you have added a few wines like you did in the local storage demo, open up your favorite HTTP sniffer. Mine is Fiddler. Take a look at the traffic to prove to yourself that you are accessing the cloud. Here is what it looks like for me:
In my next post, I will illustrate how you can expose your own custom services in Windows Azure. Catch you soon…
Azure Application Part 1: Setup and running “Hello World”
This is part 1 in this series where I am building an Azure shopping cart application from the ground up. In this post, I will illustrate how to setup your development environment, setup your Azure Services Developer Portal, including the process of requesting a token. I will then build out a simple hello world example, run it in the development fabric, debug it and finally publish it to the cloud. If you are already familiar with these topics and are already set up, please feel free to go directly to part II (if it is published).
Watch the Screencast
Setting Up Your Environment
As I mentioned, the first few posts of this series deal strictly with Windows Azure offerings (we will be working with .NET Services and Sql Data Services in later posts). This greatly simplifies setting up our development environment. For this post, I will limit the setup information to what is necessary for Windows Azure. As I delve into other areas, I will provide the necessary setup info.
Development Environment
A great thing about working with Windows Azure is that we have a simulated environment for you for development and testing. We simulate both the Windows Azure Fabric, as well as Windows Azure Storage on you local machine so you are able to build and test applications taking advantages of these services without deploying to or accessing the cloud. All you need to do is to install the following:
You can go here to see details about pre-requisites for the SDK, but for your convenience, I have summarized below:
- Operating System
- (for x86 version of SDK) – 32-bit editions of Windows Vista SP1 or Windows Server 2008.
- (for x64 version of SDK) – 64-bit edition of Windows Vista® SP1 or Windows Server® 2008
- .NET Framework 3.5 sp1
- Sql Server
- Express 2005
- Express 2008
- Local Instance of 2005, 2008 – See here for more details
- Internet Information Services (IIS) 7.0 must be enabled, with ASP.NET and Windows Communication Foundation (WCF) HTTP Activation – Click here for details how to configure
The prerequisites for the Visual Studio tools include everything above plus:
- Microsoft Visual Studio 2008 SP1 or Microsoft Visual Web Developer 2008 Express Edition with SP1
- Hotfix: Native Debugging Improvements
- Hotfix: Improve Visual Studio Stability
- Hotfix: Support for FastCGI on the Development Fabric
Set Up Your Windows Azure Account
With your development environment set up, you have everything you need to get started developing our Azure store sample application. However, you might want to actually deploy this code to the cloud. For that you are going to need an Azure account. We are currently in CTP, so there is no charge for this account (that will chance when we go to release). You do, however, need a token.
To Request A Token:
- Navigate to www.microsoft.com/azure. Click on Try It Now
- Click on Try It Now to register with Connect and Request a Token
- Log In with your Windows Live ID (you will need to create an account if you don’t already have one)
- You will then have to complete the registration information (no screenshot required)
- Click on the connection directory tab
- Scroll until you see Azure Service Invitations
- You are registered and should see a page like this:
To Setup Your Azure Services Developer Portal
- Navigate to https://lx.azure.microsoft.com
- Log In with your live id
- Fill in your country and lanugage and press I Agree to create a new account
- You will be re-directed to a confirmation page. Press continue
- You will be redirected to a page where you can redeem your invitation token. This token is necessary to create a Hosted Services project, as well as a Storage project. Don’t worry about closing the page or pressing cancel. You will be re-directed here the next time you log in. As I annotated below, you may have to wait a bit to receive your token (i.e. don’t proceed directly to Outlook and continually press refresh until you receive it). We are in CTP and have a limited number of tokens to hand out at any given time.
- Once you have your token entered appropriately, you will no longer see this page. You will instead be re-directed to a page in the portal where you can create a project. Here is what you would see if you chose ‘Cancel’ on the previous page or if you click the ‘New Project’ link under the ‘Summary Tab’.
- Here is the view you would see if you had entered a valid token:
- You are now ready to create your Hosted Services Project. Click on ‘Hosted Services’ to add a new Hosted Services project.
- On the next page, enter the following information:
- Project Label – Enter a label for your Hosted Services project. This label will be exposed on the Azure Services Developer Portal
- Project Description – Enter a description of the project you will be hosting
- On the next page, enter a service name – a unique service / domain name to create the unique DNS name. You can check on the availability of service names. After you have settled on a unique service name, press the ‘Create’ button.
- Your project is now created and you are ready to deploy a solution. We will get to that later.
* You can also take a look at the How Do I: Get Started Developing with Windows Azure? and the How Do I: Deploy a Windows Azure Application? screencast for walkthroughs on getting started with Windows Azure and deploying a Windows Azure Application.
Creating our Cloud Project in Visual Studio
Assuming that you set up your development environment as described above, you are ready to create your Cloud project. In this part, we are going to create a “Hello World” web application, test it on the local development fabric and deploy it to the cloud. In part II, we will access data from Azure Table Storage. While you can also use Visual Web Developer Express, I am going to be using Visual Studio. Let’s get started:
Create the Cloud Project
- Choose File > New > Project from the Visual Studio Menu
- Choose Cloud Service > Web Cloud Service
- That’s it!
What was created?
It is kind of funny how I sometimes view project templates. I almost assign some kind of magical value to them – like they just created life – when in reality, they are just templates. They set up project files, add appropriate code files and set up config appropriately. Perhaps I assign the magical value in the fact that it is so hard to create a good project template. That should change with future versions of VS. Anyhow, I digress. The template created 2 projects. The goals of these projects are as follows:
A Cloud Service Project
- Allows you to build and package your cloud application to run in the local development fabric
- Allows you to debug your cloud application in the local development fabric
- Allows you to build and package your cloud application to deploy to the cloud
- Stores configuration settings that apply to all instances of each role
- Allows you to configure the number of instances to be created for each role
A Web Role
A web role in this template is really just an ASP.NET application. We have created additional web role projects, including a Cgi Web Role which allows you to host PHP and Ruby apps. This template, however creates an ASP.NET application.
Add Some Code
- Add a label to Default.aspx, giving it an ID and setting runat=”server”.
- Add some code to Default.aspx.cs that executes on the server that sets the text of the label. It doesn’t matter what you put here, we just want to illustrate that the server is doing some work and this is not simply a static page.
Run In The Development Fabric
Run It
Press F5 or the Start Debugging button to run the application in the development fabric. Here is the result:
What Happened
The Visual Studio tool do some nice work for you. Here is what happens.
- Visual studio created a Windows Azure Service Package. This is the same package that is used to deploy to the web. However, in that instance, the package is zipped and encrypted. When running in the local development fabric, the extension of the package is csx and if you are running with debug symbols, you will find this in the debug directory. (See this post by Jim Nakashima for more information on how the service package is created)
- VS ensures that development storage is started
- VS ensures that the development fabric is started and deploys your package to the fabric (CSRun is the exe that does this)
- If you are running with debug symbols, Visual Studio will attach the debugger to a role running in the development fabric
(See this documentation for more information on the development fabric)
Debug It
Set a breakpoint on our code that sets the text of the label and start with debugging. Here is what you see:
It is that easy to debug our applications. Please note that it is not possible to attach a debugger to instances running in the cloud. For those situations, you need to use logging appropriately. We will cover that in future posts.
Deploy Our Application To The Cloud
* This section assumes that you have created a Windows Azure account, received your token and redeemed your invitation token as detailed above. It also assumes that you have created a Hosted Services project. I will use the token <accountName> to represent the label for the account.
Remember that when we publish to the cloud, we are packaging the application in the exact same way as when we are running it in the development fabric. The only difference is that the file is zipped and encrypted. Oh, and it has a different extension.
Here is the process to deploy to the cloud:
- (optional) Set the application id in the project properties from your Hosted Service Application ID
- Right-Click on the cloud services project (AzureStore) > Publish
- A browser will be launched and it will automatically navigate you to the appropriate project if you completed step 1. Otherwise, navigate to the Hosted Service project where you want to deploy. An explorer window also opened to the location where the cspkg (encrypted, zipped project) and the cscfg files are.
- Click on the Deploy button under Staging
- Click on the Browse buttons and navigate to the publish directory under your project. It is the directory the explorer opened to.
- Click Deploy. This process may take a few minutes.
- Press Run. This process may also take a few minutes.
- When the WebRole reads ‘Running’, you are ready to test.
- Click on the ‘Web Site Url’ link.
- That is it, you are running in the cloud! You are in staging, but feel free to swap it to production.
In my next post, I will set up Azure Table Storage. I will create our Wine table for the catalog, write some code to add wines and fetch wines. I will then write some simple aspx pages to consume that code. Lastly, I will target the cloud instead of the local development environment. Until then…
Building An Azure Application From The Ground Up
I have decided to start a multi-part blog/screencast series on developing an Azure application from the ground up. There are 2 approaches one can take here: 1) Write the completed application first and then break it down into consumable pieces, with each piece becoming a blog post and/or screencast or 2) Write the application as you go along. I am going to use a hybrid approach. I have started an application, but will be adding and changing pieces as I move along. Part of my reasoning is that, at the time of writing this post, not all of the Azure services are available, the most interesting of which is the new implementation of SDS (See Nigel Ellis’ MIX Session for more information).
Screencasts
- Part I: Setup and running "Hello World"
- Part 2: Working With Azure Table Storage
- (deep dive) Understanding The Azure Table Storage API
- Part 3: Hosting Web Services and Silverlight
Blog Posts
- Part 1: Setup and running “Hello World”
- Part 2: Working With Azure Table Storage
- (deep dive) Understanding The Azure Table Storage API
- Part 3: Hosting Web Services And Silverlight
The Sample Application
The sample application is relatively straight forward (at least to begin with). It is re-using the same UI I used for a series I did on REST in WCF. I will be building a shopping cart application. The goal of this application is to illustrate various features of Windows Azure and in coming weeks, portions of .NET Services. The first few posts will concentrate on Windows Azure, our Cloud Operating System. I will illustrate things like the developer fabric, hosting various pieces of an application in the cloud (web pages, services, Silverlight components), as well as working with Azure Table Storage. From there, we will keep going, adding and updating pieces of the application.
I look forward to your feedback, so please leave a comment!


Email Me