Beyond developing apps and games with Silverlight and XNA, take advantage of the new emulator to view and test your new HTML5 websites.
Continue Reading...Archives For Visual Studio 2010
About a month ago, I wrote an article intended to help you fill some of the gaps left by the missing SQL Server Compact database. Since your Windows Phone 7 Silverlight app is consuming an ObservableCollection of objects streaming down from Windows Azure and SQL Azure, it makes sense to organize those objects in a database-like format that’s easy to work with. If you’ve ever worked with Remote Data Access (RDA) in the past, the notion of pre-fetching multiple tables to work with locally should look familiar.
In this case, each ObservableCollection represents a table, each object represents a row, and each object property represents a column. I had you create a Singleton class to hold all these objects in memory to serve as the database. The fact that Silverlight supports Language Integrated Query (LINQ) means that you can use SQL-like statements to work with the multiple, ObservableCollections of objects.
If you’re wondering why I have you cache everything in memory in a Singleton, there’s a few reasons. For starters, it makes it easy to query everything with LINQ with the fastest performance possible for single and multi-table JOINs. Secondly, I don’t represent a Microsoft product group and therefore wouldn’t engineer an unsupported provider that can query subsets of serialized data from files residing in Isolated Storage. Finally, I don’t want you to accidentally find yourself with multiple instances of the same ObservableCollection when pulling data down from Azure or loading it from Isolated Storage. Forcing everything into a Singleton prevents you wasting memory or updating objects in the wrong instance of an ObservableCollection. An inconsistent database is not a good thing. Don’t worry, you can control which tables are loaded into memory.
So what is this article all about and what are the “improvements” I’m talking about?
This time around, I’m going to focus on saving, loading and deleting the serialized ObservableCollections from Isolated Storage. In that last article, I showed you how to serialize/de-serialize the ObservableCollections to and from Isolated Storage using the XmlSerializer. This made it easy for you to save each table to its own XML file which sounds pretty cool.
So what’s wrong with this?
Saving anything as XML means that you’re using the largest, most verbose form of serialization. After hearing me preach about the virtues of doing SOA with WCF REST + JSON, using the XmlSerializer probably seems out of place. Luckily, the DataContractJsonSerializer supported by Silverlight on Windows Phone 7 gives you the most efficient wire protocol for data-in-transit can also be used to save those same .NET objects to Isolated Storage. So the first improvement in this article comes from shrinking the size of the tables and improving the efficiency of the serialization/de-serializing operations to Isolated Storage using out-of-the-box functionality.
While going from XML to JSON for your serializing might be good enough, there’s another improvement in the way you write the code that will make this much easier to implement for your own projects. A look back to the previous article reveals a tight coupling between the tables that needed to be saved/loaded and the code needed to make that happen. This meant that you would have to create a SaveTable and LoadTable method for each table that you wanted to retrieve from Azure. The new code you’re about to see is generic and allows you to use a single SaveTable and LoadTable method even if you decide to download 100 tables.
Enough talk already, let’s see some code. Launch your ContosoCloud solution in Visual Studio and open Database.cs. I want you to overwrite the existing code with the code shown below:
using System;
using System.Net;
using System.Windows;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization.Json;
namespace ContosoPhone
{
sealed class Database
{
//Declare Instance
private static readonly Database instance = new Database();
//Private Constructor
private Database() { }
//The entry point into this Database
public static Database Instance
{
get
{
return instance;
}
}
//Serialize ObservableCollection to JSON in Isolated Storage
public void SaveTable<T>(T tableToSave, string tableName)
{
if (tableToSave != null)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = store.CreateFile(tableName + ".txt"))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(stream, tableToSave);
}
}
}
else
{
throw new Exception("Table is empty");
}
}
//Deserialize ObservableCollection from JSON in Isolated Storage
public T LoadTable<T>(T tableToLoad, string tableName)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(tableName + ".txt"))
{
using (IsolatedStorageFileStream stream = store.OpenFile(tableName + ".txt", System.IO.FileMode.Open))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(stream);
}
}
else
{
throw new Exception("Table not found");
}
}
}
//Delete ObservableCollection from Isolated Storage
public void DropTable(string tableName)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(tableName + ".txt"))
{
store.DeleteFile(tableName + ".txt");
}
else
{
throw new Exception("Table not found");
}
}
}
//Declare Private Table Variables
private ObservableCollection<Customer> customerTable = null;
//Customer Table
public ObservableCollection<Customer> Customers
{
get { return customerTable; }
set { customerTable = value; }
}
}
}
Looking from top to bottom, the first change you’ll notice is the new SaveTable method where you pass in the desired ObservableCollection and table name in order to serialize it as JSON using the DataContractJsonSerializer. The next method down the list is LoadTable where you pass in the same parameters as SaveTable but you get back a de-serialized ObservableCollection. The last new method in the Database Singleton is DropTable which simply deletes the serialized table from Isolated Storage if you don’t need it anymore.
So how do you call this code?
Bring up MainPage.xaml.cs, and find the click event for Save button. Delete the existing XmlSerializer code and replace it with the following:
try
{
Database.Instance.SaveTable<ObservableCollection<Customer>>(Database.Instance.Customers, "Customers");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The code above shows you how to call the SaveTable method in the Singleton with the appropriate syntax to pass in the ObservableCollection type as well as actual ObservableCollection value and name.
Now find the click event for the Load button, delete the existing code and paste in the following:
try
{
Database.Instance.Customers = Database.Instance.LoadTable<ObservableCollection<Customer>>(Database.Instance.Customers, "Customers");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
This code looks pretty much the same as the SaveTable code except that you set Database.Instance.Customers equal to the return value from the method. For completeness sake, drop another button on MainPage.xaml and call it Drop. In its click event, paste in the following code:
try
{
Database.Instance.DropTable("Customers");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
For this code, just pass in the name of the table you want to delete from Isolated Storage and it’s gone.
It’s time to hit F5 so you can see how things behave.
When your app comes to life in the emulator, I want you to exercise the system by Getting, Adding, Updating and Deleting Customers. In between, I want you to tap the Save button, close the app, reload the app and tap the Load button and then View Customers to ensure you’re seeing the list of Customers you expect. Keep in mind that when you Save, you overwrite the previously saved table. Likewise, when you Load, you overwrite the current in-memory ObservableCollection. Additionally, Saving, Loading, and Dropping tables that don’t exist should throw an appropriate error message.
So what’s the big takeaway for these tweaks I’ve made to the in-memory database?
While switching serialization from XML to JSON is a great improvement in size and efficiency, I truly believe that making the SaveTable and LoadTable methods generic and reusable will boost developer productivity. The new ease with which you can Save and Load 1, 10 or even 1,000 tables makes this more attractive to mobile developers that need to work with local data.
So where do we go from here?
You now have some of the basic elements of a database on Windows Phone 7. You don’t have ACID support, indexes, stored procedures or triggers but you have a foundation to build on. So what should be built next?
To help ensure database consistency, I would add an AutoFlush feature next. SQL Server Compact flushes its data to disk every 10 seconds and there’s nothing to prevent you from using the SaveTable method to do the same. A timer set to fire at a user-specified interval that iterates through all the ObservableCollections and saves them will help keep your data safe from battery loss and unforeseen system failures. The fact that your app can be tombstoned at any moment when a user taps the Back button makes an AutoFlush feature even more important.
Anything else?
At the beginning of this article I mentioned RDA which is a simple form of data synchronization. It’s simple because it only tracks changes on the client but not the server. To find out what’s new or changed on the server, RDA requires local tables on the device to be dropped and then re-downloaded from SQL Server. With the system I’ve built and described throughout this series of articles, we already have this brute force functionality. So what’s missing is client-side change tracking. To do this, I would need to add code that fires during INSERTS, UPDATES, and DELETES and then writes the appropriate information to local tracking tables. To push those changes back to SQL Azure, appropriate code would need to call WCF REST + JSON Services that execute DML code on Windows Azure.
I hope with the improvements I’ve made to the in-memory database in this article, you’ll feel even more empowered to build occasionally-connected Windows Phone 7 solutions for consumers and the enterprise.
Keep coding!
-Rob
By now, you’ve heard me talk a lot about the role wireless data networks play when it comes to the success of your mobile application. They are unreliable, intermittent, highly latent and often slower than they should be due to overtaxed cellular towers and congested backhaul networks. Hopefully, you’ve built an app that tackles those challenges head-on using efficient WCF REST + JSON Services coupled with an offline data store.
So what is the user of your new application going to think when a Web Service call fails because the network is unavailable?
An end-user of your app probably won’t be too thrilled when they’re staring at an unintelligible error message. Or maybe your app will just silently fail when the Web Service call doesn’t succeed. The user might not know there’s a problem until they can’t view a list of relevant data on their phone.
This is no way to treat your prospective user-base because mobile apps should never diminish the user experience by trying to send or receive data in the absence of network connectivity.
Luckily, Silverlight on Windows Phone 7 provides you with a way to determine network connectivity.
Launch Visual Studio 2010 and load the ContosoCloud solution that we’ve been working with over the last four Windows Phone 7 Line of Business App Dev articles. First, I want you to drag an Ellipse from the Toolbox and drop it on MainPage.xaml. Name that control ellipseNet. Next, I want you to drag a TextBlock control over and drop it beneath the Ellipse. Name this control textBlockNet. Now open MainPage.xaml.cs so we can write some code.
Above the ContosoPhone namespace I want you to add:
using Microsoft.Phone.Net.NetworkInformation;
This allows you to tap into the NetworkInterface class. The next line of code I want you to add may seem a little confusing since it’s similar, yet different from Microsoft.Phone.Net.NetworkInformation. Inside the MainPage() constructor, beneath InitializeComponent();, add the following code to create an event handler:
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged += new System.Net.NetworkInformation.NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
This is the standard, cross-platform Silverlight way to create an event handler that tells you when your network address has changed. I wrote it out the long-way because it collides with the phone-specific NetworkInformation class. Don’t ask.
Underneath the line of code above, add the following:
NetworkStateMachine();
This is going to call a method you haven’t created yet.
Inside your MainPage class, the event handler your just created will appear:
void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
NetworkStateMachine();
}
As you can see, I want you to add the NetworkStateMachine(); line of code inside the event handler to execute this mysterious function. By now you’re probably saying, “Enough of the suspense already!” Below the event handler, paste in the following code:
private void NetworkStateMachine()
{
try
{
switch (NetworkInterface.NetworkInterfaceType)
{
//No Network
case NetworkInterfaceType.None:
ellipseNet.Fill = new SolidColorBrush(Colors.Red);
textBlockNet.Text = "No Network";
break;
//CDMA Network
case NetworkInterfaceType.MobileBroadbandCdma:
ellipseNet.Fill = new SolidColorBrush(Colors.Blue);
textBlockNet.Text = "CDMA";
break;
//GSM Network
case NetworkInterfaceType.MobileBroadbandGsm:
ellipseNet.Fill = new SolidColorBrush(Colors.Blue);
textBlockNet.Text = "GSM";
break;
//Wi-Fi Network
case NetworkInterfaceType.Wireless80211:
ellipseNet.Fill = new SolidColorBrush(Colors.Green);
textBlockNet.Text = "Wi-Fi";
break;
//Ethernet Network
case NetworkInterfaceType.Ethernet:
ellipseNet.Fill = new SolidColorBrush(Colors.Green);
textBlockNet.Text = "Ethernet";
break;
//No Network
default:
ellipseNet.Fill = new SolidColorBrush(Colors.Red);
textBlockNet.Text = "No Network";
break;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The switch statement above creates a state machine for your mobile application that lets it know what type of network connection you have at any given moment. Remember for this example, the sample code is running on the UI thread. Since the code is synchronous and blocking, you may want to run it on a background thread.
As you can see, the following network types are returned:
- Wireless80211 (Wi-Fi)
- Ethernet (Docked/LAN)
- MobileBroadbandGSM (GPRS/EDGE/UMTS/HSDPA/HSPA)
- MobileBroadbandCDMA (1xRTT/EV-DO)
-
None
As you’re probably thinking, the primary value in this is to know if you have any kind of network or not. Obviously, a return value of None means you shouldn’t make any kind of Web Service call.
Hit F5 in Visual Studio and let’s see what you get in the emulator:
As you can see, the ContosoCloud app detected my laptop’s Wi-Fi connection in the switch statement and therefore gave me a Green Ellipse and a TextBlock that says “Wi-Fi.” Keep in mind that the emulator doesn’t behave the same way as an actual phone so changing my laptop’s networking while the mobile app is running won’t trigger the NetworkChange_NetworkAddressChanged event handler. If you close the app, turn off Wi-Fi on your laptop and then restart the app, it will correctly report that no network is available.
So why would you want to know about all the other network return types?
In working with customers all around the world who use Pocket PCs, Windows Mobile devices and Windows Phones, it has become evident that there is always a “cost” in doing anything over the network. Not everyone has unlimited, “all-you-can-eat” data plans for their employees. Some companies have very low monthly data usage limits for each employee that has been negotiated with one or more mobile operators. For these organizations, it’s not enough to know if the network is present or not. They need to know what kind of network is available so their mobile application can make intelligent decisions.
If I need to download a large amount of data in the morning to allow me to drive my delivery truck route, I probably should only perform this operation over docked Ethernet or Wi-Fi. This gives me the network speed I need to move a lot of data and I don’t incur any costs with my mobile operator.
If I’ve captured small amounts of data in the field that I need to send back to HQ in near real-time, then a return value of MobileBroadbandGSM or MobileBroadbandCDMA is perfect. This would also be appropriate if my app is making lightweight remote method calls via Web Services as well. The use of WCF REST + JSON is probably making a lot of sense now.
If I’ve captured large amounts of data in the field or I’m batching up several data captures throughout the day, it would make more sense to use Ethernet or Wi-Fi when I returned to the warehouse or distribution center. On the other hand, if I have a high enough data usage limit or no limit at all, the MobileBroadbandGSM/CDMA would be fine.
Keep in mind that this guidance is just as valuable for B2C and Consumer apps as well. If you’re building a connected mobile app of any kind, the information I’ve discussed in this article will ensure that you’re always providing a great user experience.
Delighting the end-user is what it’s all about!
-Rob
In my last article of this series, you finally got to consume wireless-friendly WCF REST + JSON Services from both Windows Server and Windows Azure with data coming from SQL Server/SQL Azure. You now have an ObservableCollection of Customer objects residing in a Singleton on your Windows Phone 7 device. This Singleton looks similar to an in-memory database and the Customers property works like a table.
So now what?
If you’re like me, you probably want to display the list of Customers in the UI. You might also want to perform other local operations against this data store. You could add a new Customer and update or even delete an existing one.
I’m going to apologize in advance for not doing the MVVM thing that everyone seems to be into these days and get right to the point. Drag a button on to MainPage.xaml and call it View Customers. While you’re at it, drag a listbox below the button and name it listBoxCustomers. Double-click on this Button and add the following code to the click event:
try
{
if (Database.Instance.Customers != null)
{
listBoxCustomers.DisplayMemberPath = "Name";
listBoxCustomers.ItemsSource = Database.Instance.Customers;
}
else
{
MessageBox.Show("The Customer Table is Empty");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
In the simple code above, you set the listbox’s ItemsSource equal to the Customer collection in the Database Singleton and set the DisplayMemberPath property equal to the Name property of the Customer objects.
Hit F5 to start debugging this Windows Phone 7 + Azure solution. As usual, a web page and the emulator will launch. Tap the Get Customers button to pull the Customer data back from the WCF REST service. Next, tap on the View Customers button to display the list of Customers from the in-memory database as shown in the picture below:
Now it’s time to add a new Customer so drop a button underneath the listbox and call it Add Customer. Creating a new Customer object requires setting values for 8 properties. Instead of having you add 8 textboxes to type in the info, I’ll keep in simple and let you add it in code. In the click event of the button, paste in the code you see below:
try
{
if (Database.Instance.Customers != null)
{
Customer customer = new Customer();
customer.CustomerId = 5;
customer.DistributionCenterId = 1;
customer.RouteId = 1;
customer.Name = "ABC Corp";
customer.StreetAddress = "555 Market Street";
customer.City = "Seattle";
customer.StateProvince = "WA";
customer.PostalCode = "98987";
Database.Instance.Customers.Add(customer);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
After setting all the properties (Columns), you add the Customer object (Row) to the Customers property (Table), in the Singleton Database. Hit F5, tap the Get Customers button, tap the View Customers button and then tap the Add Customer button. Through the magic of simple data-binding, you should see the new “ABC Corp” show up in the listbox as shown below:
Now that you’ve added a new Customer, it’s time to update it because the president of the company decided to change the name. Drag a new button and drop it underneath the Add Customer button. Call it Update Customer and in it’s click event, paste in the following code:
try
{
if (Database.Instance.Customers != null)
{
foreach (Customer c in Database.Instance.Customers)
{
if (c.Equals((Customer)listBoxCustomers.SelectedItem))
{
c.Name = "XYZ Inc";
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The code above loops through the Customers ObservableCollection until it finds a match for the item that’s been selected in the listbox. When it finds that match, it updates the Name property to “XYZ Inc” which will automatically update what the user views in the listbox.
Hit F5, tap the Get Customers button, tap the View Customers button and then tap the Add Customer button. Now tap on “ABC Corp” in the listbox to highlight it. Clicking the Update Customer button will change it before your eyes.
It turns out that “XYZ Inc” went out of business because the president was an idiot so you need to delete it. Guess what, you need yet another button beneath the Update Customer button. Call it Delete Customer and in it’s click event, paste in the following code:
try
{
if (Database.Instance.Customers != null)
{
Database.Instance.Customers.Remove((Customer)listBoxCustomers.SelectedItem);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
In the code above, the Customer object that matches the item selected in the listbox is removed from the Customers ObservableCollection. Pretty simple stuff in this case.
To find out for sure, hit F5, tap the Get Customers button, tap the View Customers button and then tap the Add Customer button. Now tap on “ABC Corp” in the listbox to highlight it. Clicking the Update Customer button will change it to “XYZ Inc.” Highlighting “XYZ Inc” and clicking the Delete Customer button will cause this defunct company to disappear as shown below:
Now suppose you only want to display the Customers from Seattle and not the Eastside. A little LINQ will do the trick here. Drag and drop a new button called Seattle next to the Test Uri button and paste the following code in the click event:
if (Database.Instance.Customers != null)
{
IEnumerable<Customer> customers = from customer in Database.Instance.Customers
where customer.DistributionCenterId == 1
select customer;
listBoxCustomers.DisplayMemberPath = "Name";
listBoxCustomers.ItemsSource = customers;
}
else
{
MessageBox.Show("The Driver Table is Empty");
}
In the code above, I set an IEnumerable<Customer> variable equal to the Customers table where the DistributionCenterId is equal to 1. Since the DistributionCenter #1 serves the Seattle area, I know the listbox will be filled with just Adventure Works LLC and City Power & Light. Start debugging and test it for yourself.
The last thing you need to do with local data is store it offline since you can’t always count on the network being there. Luckily we’ve got Isolated Storage to serialize stuff. In order to work with Isolated Storage, I need you to add using System.IO.IsolatedStorage; at the top of the class. Since in this example I’ll demonstrate XML Serialization of the Customers ObservableCollection, I’ll need you to add a reference to System.Xml.Serialization and then add using System.Xml.Serialization; at the top of the class. With that plumbing in place, let’s write some actual code.
Drag and drop another button called Save next to the Get Customers button and paste the following code in the click event:
if (Database.Instance.Customers != null)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = store.CreateFile("Customers.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<Customer>));
serializer.Serialize(stream, Database.Instance.Customers);
}
}
}
In the code above, you use the combination of IsolatedStorageFile and IsolatedStorageFileStream to write data to Isolated Storage. In this case, you’re going to create an XML file to save the Customers ObservableCollection of Customer objects. Remember back in the 80’s when databases used to save each table as an individual file? I’m thinking of DBase III+, FoxPro, and Paradox at the moment. Anyway, this is exactly what happens here using the power of the XmlSerializer. Feel free to debug and step through the code to ensure that it executes without error.
To complete the picture, you need to be able to retrieve the Customers ObservableCollection from Isolated Storage and work with the data without ever having to call the WCF REST services. Drag and drop one last button called Load next to the View Customers button and paste the following code in the click event:
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists("Customers.xml"))
{
using (IsolatedStorageFileStream stream = store.OpenFile("Customers.xml", System.IO.FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<Customer>));
Database.Instance.Customers = (ObservableCollection<Customer>)serializer.Deserialize(stream);
}
}
}
The code above does the reverse of the previous Save code by opening the Customers.xml and re-hydrating those objects back into the Customers table using the XmlSerializer. This is pretty cool stuff.
To make it all real, hit F5 to start debugging this completed mobile project. When the app loads, tap the Get Customers button to retrieve the data and then tap View Customers to verify that you can see the data. Now I want you to tap the Save button to serialize the Customers to an XML file in Isolated Storage. Lastly, I want you to tap on the Back button to close the application.
Hit F5 again to fire up the application. This time, I don’t want you to retrieve the data from Azure. Instead, I want you to tap the Load button to de-serialize the Customer objects from XML. Now for the moment of truth. Tap the View Customers button to see if you’re actually working with an offline database. Hopefully, your app will look like the picture below:
Congratulations! You’ve made it to the end of this series of articles on building an occasionally-connected Windows Phone 7 application that works with WCF REST + JSON Services in Windows Azure. Furthermore, you’re now pulling data down from SQL Azure and you’re working with it locally using a simple in-memory database that you built yourself. I’m hoping that you’ll now feel empowered to go build industrial-strength mobile solutions for your own company or your customers.
Keep coding!
-Rob
Ever since my last blog post where I demonstrated how to create lightweight WCF REST + JSON services for consumption by Windows Phone 7, I’ve received many requests from folks wanting to know how to do the same thing from Windows Azure. Using Visual Studio 2010, the Azure Development Fabric and SQL Server, I will show you how to move this code to the cloud.
Fire up VS2010 and create a new cloud project (you’ll be prompted to download all the Azure bits if you haven’t done so already).
Select WCF Service Web Role and move it over to your Cloud Service Solution. Rename it to AzureRestService and click OK.
You’ll then be presented with the default Service1.svc.cs SOAP web service that implements the IService1.cs Interface. Needless to say, you’ll need to makes some modifications to these two files as well as Web.config if you want to be a true RESTafarian.
In Service1.svc.cs, delete the GetDataUsingDataContract method but leave the GetData method since you’ll use it to perform an initial test.
Next, open IService1.cs and delete the GetDataUsingDataContract [OperationContract] as well as the CompositeType [DataContract]. You should be left with the simple GetData [OperationContract].
Open Web.config. You’ll notice that it’s already pretty full of configuration items. After the closing </serviceBehaviors> tag, tap on your Enter key a few times to give you some room to insert some new stuff. Insert the following just below the closing </serviceBehaviors> tag and just above the closing </behaviors> tag as shown:
<endpointBehaviors>
<behavior name="REST">
<webHttp />
</behavior>
</endpointBehaviors>
This provides you with the all-important webHttp behavior that enables lean REST calls using HTTP Verbs.
Below the closing </behaviors> tag and above <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />, insert the following as shown:
<services>
<service name="AzureRestService.Service1">
<endpoint address="" behaviorConfiguration="REST" binding="webHttpBinding" contract="AzureRestService.IService1" />
</service>
</services>
Here is where we define our service name and contract. It’s also where we point our behaviorConfiguration at the webHttp behavior you named “REST” and set the binding to webHttpBinding.
Now it’s time to decorate your interface’s [OperationContract] with a WebGet attribute and utilize a UriTemplate to give the Windows Phone 7 caller a web-friendly Uri to call. So beneath [OperationContract] and above string GetData(int value);, squeeze in the following:
[WebGet(UriTemplate = "/getdata?number={value}", BodyStyle = WebMessageBodyStyle.Bare)]
Since we want to call the GetData method via a GET request, we use WebGet and then we set our UriTemplate to something that anyone could access via their browser. Lastly, we strip out all unnecessary junk by setting WebMessageBodyStyle.Bare.
It’s convenient that I mentioned using a browser to access this new REST service because that’s exactly how we’re going to test it. Hit F5 in Visual Studio to fire up the Azure Development Fabric and start your Web Role. Internet Explorer will come up and you’ll probably see an Error page because it points to the Root of your Role Site. This is expected behavior. In order to test the service, type the following in the IE address bar:
http://127.0.0.1:81/service1.svc/getdata?number=5
This points to a loopback address on your computer with a port number of 81. If your environment uses a different port, then just change what you pasted in as appropriate. After the port number and “/”, you type in the name of the service you created which is service1.svc. After the next “/”, you type the format you described in the UriTemplate. You can type any Integer you wish and if everything works, the browser will display the following result:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You entered: 5</string>
With your test REST service working from your local Azure Development Fabric, it’s time to bring over the business logic from my last blog post where I showed you how to return Customer information from an on-premise WCF Service connected to SQL Server. I don’t necessarily expect you to have a SQL Azure account so you’ll add a connection string to Web.config that points to a local SQL Server Express instance. Don’t worry, you can swap this connection string out later to point to our awesome cloud database. Beneath the closing </system.web> tag and above the <system.serviceModel> tag, insert the following:
<connectionStrings>
<add name="ContosoBottlingConnectionString" connectionString="Data Source=RTIFFANY2\SQLEXPRESS;Initial Catalog=ContosoBottling;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
This is the same connection string from the last blog post and you’ll definitely need to modify it to work with both your local SQL Server instance and SQL Azure when you’re ready to deploy. Bear with me as the rest of this blog post will be a large Copy and Paste effort.
Open IService1.cs and add the following:
using System.Collections.ObjectModel;
and
[OperationContract]
[WebGet(UriTemplate = "/Customers", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
ObservableCollection<Customer> GetCustomers();
Open Service1.svc.cs and add the following:
using System.Web.Configuration;
using System.Collections.ObjectModel;
using System.Data.SqlClient;
and
//Get the Database Connection string
private string _connectionString = WebConfigurationManager.ConnectionStrings["ContosoBottlingConnectionString"].ConnectionString;
and
public ObservableCollection<Customer> GetCustomers()
{
SqlConnection _cn = new SqlConnection(_connectionString);
SqlCommand _cmd = new SqlCommand();
_cmd.CommandText = "SELECT CustomerId, DistributionCenterId, RouteId, Name, StreetAddress, City, StateProvince, PostalCode FROM Customer";
try
{
_cn.Open();
_cmd.Connection = _cn;
ObservableCollection<Customer> _customerList = new ObservableCollection<Customer>();
SqlDataReader _dr = _cmd.ExecuteReader();
while (_dr.Read())
{
Customer _customer = new Customer();
_customer.CustomerId = Convert.ToInt32(_dr["CustomerId"]);
_customer.DistributionCenterId = Convert.ToInt32(_dr["DistributionCenterId"]);
_customer.RouteId = Convert.ToInt32(_dr["RouteId"]);
_customer.Name = Convert.ToString(_dr["Name"]);
_customer.StreetAddress = Convert.ToString(_dr["StreetAddress"]);
_customer.City = Convert.ToString(_dr["City"]);
_customer.StateProvince = Convert.ToString(_dr["StateProvince"]);
_customer.PostalCode = Convert.ToString(_dr["PostalCode"]);
//Add to List
_customerList.Add(_customer);
}
return _customerList;
}
finally
{
_cmd.Dispose();
_cn.Close();
}
}
As you can see, the only remaining error squigglies refer to the lack of the Customer class I discussed in the on-premise WCF project from the last blog post. To add it, I want you to right-click on your AzureRestService project and select Add | Class and name the class Customer.
Now I want you to paste the code below into this new class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using System.ComponentModel;
namespace AzureRestService
{
[DataContract()]
public class Customer : INotifyPropertyChanged
{
public Customer() { }
private int customerId;
private int distributionCenterId;
private int routeId;
private string name;
private string streetAddress;
private string city;
private string stateProvince;
private string postalCode;
[DataMember()]
public int CustomerId
{
get { return customerId; }
set
{
customerId = value;
NotifyPropertyChanged("CustomerId");
}
}
[DataMember()]
public int DistributionCenterId
{
get { return distributionCenterId; }
set
{
distributionCenterId = value;
NotifyPropertyChanged("DistributionCenterId");
}
}
[DataMember()]
public int RouteId
{
get { return routeId; }
set
{
routeId = value;
NotifyPropertyChanged("RouteId");
}
}
[DataMember()]
public string Name
{
get { return name; }
set
{
name = value;
NotifyPropertyChanged("Name");
}
}
[DataMember()]
public string StreetAddress
{
get { return streetAddress; }
set
{
streetAddress = value;
NotifyPropertyChanged("StreetAddress");
}
}
[DataMember()]
public string City
{
get { return city; }
set
{
city = value;
NotifyPropertyChanged("City");
}
}
[DataMember()]
public string StateProvince
{
get { return stateProvince; }
set
{
stateProvince = value;
NotifyPropertyChanged("StateProvince");
}
}
[DataMember()]
public string PostalCode
{
get { return postalCode; }
set
{
postalCode = value;
NotifyPropertyChanged("PostalCode");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
As I mentioned in the last article, this class is a little overkill since it inherits from INotifyPropertyChanged and adds all the code associated with firing NotifyPropertyChanged events. I only do this because you will use this same class in your Windows Phone 7 project to support two-way data binding.
The Customer table you’ll be pulling data from is shown in SQL Server Management Studio below:
We’re now ready to roll so hit F5 in Visual Studio to debug this new cloud solution in the Azure Development Fabric. When Internet Explorer comes up, type the following in the IE address bar:
http://127.0.0.1:81/service1.svc/customers
You might be surprised to see the following dialog pop up instead of XML rendered in the browser:
The reason you see this is because you’re returning the data objects in wireless-friendly JSON format. Notice that the dialog say the Unknown file type is only 671 bytes. This is a good thing. Click the Save button and save this file to your desktop.
Now find the customer file on your desktop and rename it to customer.txt so you can view it in Notepad. Double-click on this text box to reveal the tiny, JSON-encoded data in Notepad that you just looked at in the previous SQL Server Management Studio picture.
Conclusion
If you followed me through this example and all the code executed properly, you now know how to build Windows Azure REST + JSON services designed to conquer those slow, unreliable, and highly-latent wireless data networks we all deal with all over the world. When combined with my last article, both your on-premise and Windows Azure bases are covered with WCF. The only thing left to do is sign up for an Windows Azure Platform account and move this Web Role and SQL Azure database to cloud. In my next article, I’ll show you how to use the WebClient object from Silverlight in Windows Phone 7 to call these services.
Keep coding,
-Rob











The Microsoft Windows Mobile Line of Business Solution Accelerator
Getting Started with Java on PDAs
JSP vs JSP
Using Servlet Debugger 2.0
Java Web Server and Dynamic Page Compilation
How to Upgrade JBuilder's Speed and Its Servlets
Servlet Development with JBuilder