Windows Phone 7 Line of Business App Dev :: Improving the In-Memory Database

Phone 7

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.

phone7

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

Sharing my knowledge and helping others never stops, so connect with me on my blog at http://robtiffany.com , follow me on Twitter at https://twitter.com/RobTiffany and on LinkedIn at https://www.linkedin.com/in/robtiffany

Sign Up for my Newsletter and get a FREE Chapter of “Mobile Strategies for Business!”

[mc4wp_form id=”5975″]

Windows Phone 7 Line of Business App Dev :: Network Awareness

Phone 6

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:

phone6

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

Sharing my knowledge and helping others never stops, so connect with me on my blog at http://robtiffany.com , follow me on Twitter at https://twitter.com/RobTiffany and on LinkedIn at https://www.linkedin.com/in/robtiffany

Sign Up for my Newsletter and get a FREE Chapter of “Mobile Strategies for Business!”

[mc4wp_form id=”5975″]

Windows Phone 7 Line of Business App Dev :: Working with an In-Memory Database

Phone3

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:

phone1

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:

phone2

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.

phone3

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:

phone4

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:

phone5

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

Sharing my knowledge and helping others never stops, so connect with me on my blog at http://robtiffany.com , follow me on Twitter at https://twitter.com/RobTiffany and on LinkedIn at https://www.linkedin.com/in/robtiffany

Sign Up for my Newsletter and get a FREE Chapter of “Mobile Strategies for Business!”

[mc4wp_form id=”5975″]

Windows Phone 7 Line of Business App Dev :: Moving your WCF REST + JSON Service to Windows Azure

Azure2

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).

Azure1

Select WCF Service Web Role and move it over to your Cloud Service Solution.  Rename it to AzureRestService and click OK.

Azure2

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.

Azure3

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.

Azure4

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:

Azure5

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:

Azure6

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.

Azure7

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

Sharing my knowledge and helping others never stops, so connect with me on my blog at http://robtiffany.com , follow me on Twitter at https://twitter.com/RobTiffany and on LinkedIn at https://www.linkedin.com/in/robtiffany

Sign Up for my Newsletter and get a FREE Chapter of “Mobile Strategies for Business!”

[mc4wp_form id=”5975″]

Windows Phone 7 Line of Business App Dev :: Building a WCF REST + JSON Service

Visual Studio

Let’s start at the server and work our way to the phone.  Anyone who knows me is probably aware that I come from a wireless background so I’m always obsessed with things like coverage, bandwidth and latency when it comes to building mobile systems.  The only thing I assume in mobile development is frequent network dropouts and 28.8 kb/s modem speeds.  Think Compuserve.  For device apps to be successful, they must pre-fetch the data they need and cache it offline so a user can keep working when the network is not around.  This is not typical SOA, calling Web Services on-demand to help drive your application.  If your connectivity is that perfect, then build a mobile web site.  Additionally, they must first save captured data locally and only try to upload it to the server when network connectivity is available.  Never get caught in the trap of assuming ubiquitous network availability.

Networking + Wire Protocols

If you’ve looked at the Networking in Silverlight for Windows Phone 7 documentation on MSDN, you might have noticed that a number of things are missing:

  • WCF RIA Services
  • WCF Data Services (OData)
  • Duplex Communication over HTTP
  • Sockets
  • UDP Multicast Client
  • NTLM Auth
  • RSS/ATOM Feeds
  • Custom Bindings
  • JSON Serialization

I decided to focus on the networking capabilities that did work out of the box so that I could continue to build large-scale mobile/wireless solutions for our customers.  We’ve got SOAP and REST + Basic Authentication.  That’s right, you can add a Service Reference to an ASMX or WCF Web Service and you can pass your credentials to IIS with Basic Auth as long as you remember to wrap that clear text with SSL.  What I’m truly interested in is using the smallest, most efficient wire protocol possible to traverse all those unreliable wireless networks.  I’ve looked at various ways to do something simple like return a short list of Customers to a Windows Phone 7 device.  Some wire protocols are more efficient than others.  For instance:

  • An OData list of just 8 Customers from a WCF Data Service was extremely verbose and weighed in at a whopping 8.5 kb.  Yikes!

<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes” ?>
– <feed xml:base=”
http://localhost:33779/WcfDataService1.svc/” xmlns:d=”http://schemas.microsoft.com/ado/2007/08/dataservices” xmlns:m=”http://schemas.microsoft.com/ado/2007/08/dataservices/metadata” xmlns=”http://www.w3.org/2005/Atom”>
<title type=”text”>Drivers</title>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers</id>
<updated>2010-05-24T22:12:38Z</updated>
<link rel=”self” title=”Drivers” href=”Drivers” />
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(1)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(1)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(1)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(1)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>1</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>1</d:DistributionCenterId>
<d:FirstName>Rob</d:FirstName>
<d:LastName>Tiffany</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(2)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(2)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(2)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(2)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>2</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>1</d:DistributionCenterId>
<d:FirstName>Loke Uei</d:FirstName>
<d:LastName>Tan</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(3)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(3)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(3)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(3)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>3</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>1</d:DistributionCenterId>
<d:FirstName>Dan</d:FirstName>
<d:LastName>Bouie</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(4)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(4)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(4)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(4)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>4</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>1</d:DistributionCenterId>
<d:FirstName>John</d:FirstName>
<d:LastName>Dietz</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(5)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(5)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(5)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(5)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>5</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>2</d:DistributionCenterId>
<d:FirstName>Derek</d:FirstName>
<d:LastName>Snyder</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(6)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(6)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(6)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(6)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>6</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>2</d:DistributionCenterId>
<d:FirstName>Steve</d:FirstName>
<d:LastName>Hegenderfer</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(7)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(7)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(7)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(7)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>7</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>2</d:DistributionCenterId>
<d:FirstName>Chip</d:FirstName>
<d:LastName>Vollers</d:LastName>
</m:properties>
</content>
</entry>
– <entry>
<id>
http://localhost:33779/WcfDataService1.svc/Drivers(8)</id>
<title type=”text” />
<updated>2010-05-24T22:12:38Z</updated>
– <author>
<name />
</author>
<link rel=”edit” title=”Driver” href=”Drivers(8)” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/DistributionCenter” type=”application/atom+xml;type=entry” title=”DistributionCenter” href=”Drivers(8)/DistributionCenter” />
<link rel=”
http://schemas.microsoft.com/ado/2007/08/dataservices/related/Todays” type=”application/atom+xml;type=feed” title=”Todays” href=”Drivers(8)/Todays” />
<category term=”ContosoBottlingModel.Driver” scheme=”
http://schemas.microsoft.com/ado/2007/08/dataservices/scheme” />
– <content type=”application/xml”>
– <m:properties>
<d:DriverId m:type=”Edm.Int32″>8</d:DriverId>
<d:DistributionCenterId m:type=”Edm.Int32″>2</d:DistributionCenterId>
<d:FirstName>James</d:FirstName>
<d:LastName>Pratt</d:LastName>
</m:properties>
</content>
</entry>
</feed>

  • The same list of 8 Customers using SOAP and a DataSet dropped us down to 3 kb but still too big for my taste.

<?xml version=”1.0″ encoding=”utf-8″?>
<DataSet xmlns=”
http://tempuri.org/”>
<xs:schema id=”NewDataSet” xmlns=”” xmlns:xs=”
http://www.w3.org/2001/XMLSchema” xmlns:msdata=”urn:schemas-microsoft-com:xml-msdata”>
<xs:element name=”NewDataSet” msdata:IsDataSet=”true” msdata:UseCurrentLocale=”true”>
<xs:complexType>
<xs:choice minOccurs=”0″ maxOccurs=”unbounded”>
<xs:element name=”Driver”>
<xs:complexType>
<xs:sequence>
<xs:element name=”DriverId” type=”xs:int” minOccurs=”0″ />
<xs:element name=”DistributionCenterId” type=”xs:int” minOccurs=”0″ />
<xs:element name=”FirstName” type=”xs:string” minOccurs=”0″ />
<xs:element name=”LastName” type=”xs:string” minOccurs=”0″ />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata=”urn:schemas-microsoft-com:xml-msdata” xmlns:diffgr=”urn:schemas-microsoft-com:xml-diffgram-v1″>
<NewDataSet xmlns=””>
<Driver diffgr:id=”Driver1″ msdata:rowOrder=”0″>
<DriverId>1</DriverId>
<DistributionCenterId>1</DistributionCenterId>
<FirstName>Rob</FirstName>
<LastName>Tiffany</LastName>
</Driver>
<Driver diffgr:id=”Driver2″ msdata:rowOrder=”1″>
<DriverId>2</DriverId>
<DistributionCenterId>1</DistributionCenterId>
<FirstName>Loke Uei</FirstName>
<LastName>Tan</LastName>
</Driver>
<Driver diffgr:id=”Driver3″ msdata:rowOrder=”2″>
<DriverId>3</DriverId>
<DistributionCenterId>1</DistributionCenterId>
<FirstName>Dan</FirstName>
<LastName>Bouie</LastName>
</Driver>
<Driver diffgr:id=”Driver4″ msdata:rowOrder=”3″>
<DriverId>4</DriverId>
<DistributionCenterId>1</DistributionCenterId>
<FirstName>John</FirstName>
<LastName>Dietz</LastName>
</Driver>
<Driver diffgr:id=”Driver5″ msdata:rowOrder=”4″>
<DriverId>5</DriverId>
<DistributionCenterId>2</DistributionCenterId>
<FirstName>Derek</FirstName>
<LastName>Snyder</LastName>
</Driver>
<Driver diffgr:id=”Driver6″ msdata:rowOrder=”5″>
<DriverId>6</DriverId>
<DistributionCenterId>2</DistributionCenterId>
<FirstName>Steve</FirstName>
<LastName>Hegenderfer</LastName>
</Driver>
<Driver diffgr:id=”Driver7″ msdata:rowOrder=”6″>
<DriverId>7</DriverId>
<DistributionCenterId>2</DistributionCenterId>
<FirstName>Chip</FirstName>
<LastName>Vollers</LastName>
</Driver>
<Driver diffgr:id=”Driver8″ msdata:rowOrder=”7″>
<DriverId>8</DriverId>
<DistributionCenterId>2</DistributionCenterId>
<FirstName>James</FirstName>
<LastName>Pratt</LastName>
</Driver>
</NewDataSet>
</diffgr:diffgram>
</DataSet>

  • Switching to REST + XML dropped us to a much leaner 1.2 kb.

<ArrayOfDriver xmlns=http://schemas.datacontract.org/2004/07/ContosoWcfService.Models

xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”>
<Driver>
<DistributionCenterId>1</DistributionCenterId>
<DriverId>1</DriverId>
<FirstName>Rob</FirstName>
<LastName>Tiffany</LastName>
</Driver>
<Driver>
<DistributionCenterId>1</DistributionCenterId>
<DriverId>2</DriverId>
<FirstName>Loke Uei</FirstName>
<LastName>Tan</LastName>
</Driver>
<Driver>
<DistributionCenterId>1</DistributionCenterId>
<DriverId>3</DriverId>
<FirstName>Dan</FirstName>
<LastName>Bouie</LastName>
</Driver>
<Driver>
<DistributionCenterId>1</DistributionCenterId>
<DriverId>4</DriverId>
<FirstName>John</FirstName>
<LastName>Dietz</LastName>
</Driver>
<Driver>
<DistributionCenterId>2</DistributionCenterId>
<DriverId>5</DriverId>
<FirstName>Derek</FirstName>
<LastName>Snyder</LastName>
</Driver>
<Driver>
<DistributionCenterId>2</DistributionCenterId>
<DriverId>6</DriverId>
<FirstName>Steve</FirstName>
<LastName>Hegenderfer</LastName>
</Driver>
<Driver>
<DistributionCenterId>2</DistributionCenterId>
<DriverId>7</DriverId>
<FirstName>Chip</FirstName>
<LastName>Vollers</LastName>
</Driver>
<Driver>
<DistributionCenterId>2</DistributionCenterId>
<DriverId>8</DriverId>
<FirstName>James</FirstName>
<LastName>Pratt</LastName>
</Driver>
</ArrayOfDriver>

  • Switching my REST service encoding from XML to JSON to us down to a mere 639 bytes.
    • [{“DistributionCenterId”:1,”DriverId”:1,”FirstName”:”Rob”,”LastName”:”Tiffany”},{“DistributionCenterId”:1,”DriverId”:2,”FirstName”:”Loke Uei”,”LastName”:”Tan”},{“DistributionCenterId”:1,”DriverId”:3,”FirstName”:”Dan”,”LastName”:”Bouie”},{“DistributionCenterId”:1,”DriverId”:4,”FirstName”:”John”,”LastName”:”Dietz”},{“DistributionCenterId”:2,”DriverId”:5,”FirstName”:”Derek”,”LastName”:”Snyder”},{“DistributionCenterId”:2,”DriverId”:6,”FirstName”:”Steve”,”LastName”:”Hegenderfer”},{“DistributionCenterId”:2,”DriverId”:7,”FirstName”:”Chip”,”LastName”:”Vollers”},{“DistributionCenterId”:2,”DriverId”:8,”FirstName”:”James”,”LastName”:”Pratt”}]

 

Based on the title of this article, it’s probably obvious that I decided to go with REST + JSON because my customers care about speed, efficiency and reduced data costs.  I know I said JSON Serialization isn’t supported out of the box but that’s only partially true since you get the DataContractJsonSerializer to work with WCF objects encoded with JSON.  In this article, I’m going to walk you through the WCF project I built in Visual Studio 2010 so let’s get started.

Models

Since we won’t be generating a client-side proxy for your phone via adding a Service Reference or using slsvcutil.exe, then you can’t count on getting auto-generated Model objects.  This means you actually get to write some more code and build them yourself.  The Models you build on the server for your WCF Service will be the same one’s you copy to your Windows Phone 7 project so you’re client code will know what to do with them when they arrive. In order to ensure that your class and it’s properties are properly serialized for transport over the air, don’t forget to use the DataContract() and DataMember() attributes to make the magic happen.  Since I want my models to be Silverlight-friendly when it comes to data binding, I implement the INotifyPropertyChanged Interface.  While this may not seem important for the business entities you’re creating on the server, your Silverlight client needs this so I’m doing it now since I will be copying these same classes to my Windows Phone 7 project later.  The net of all this is that you add a PropertyChangedEventHandler to each class and you fire that event in each property’s setter.  This facilitates new or changed data in a bound control to update the model automatically.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using System.ComponentModel;

namespace ContosoWcfService.Models
{
[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));
}
}

    }
}

Contract

In WCF, it’s all about contract-first development so you have to start out with a public Interface.  This is your Service Contract that exposes one or more Operation Contracts.  Since we’re going with REST, and I’m retrieving data, this means I’m going to use a GET request.  The WebGet attribute allows me to specify this easily.  Had I been Inserting, Updating or Deleting data, the WebInvoke attribute would’ve helped me with my POST, PUT or DELETE.  Next up is the use of the UriTemplate.  This allows me to point to REST/SEO friendly URIs to perform my operations rather than calling web methods that are buried inside a single URI.  In this case, I just want to retrieve a list of Customers so I set the UriTemplate = “/Customers.”  Since we’re trying to avoid the kind of extra baggage you get with SOAP, I set the BodyStyle == Bare which prevents extra XML wrapping of our parameters and return values.  For my ResponseFormat property, I set the WebMessageFormat to Json instead of XML in order to send the absolute minimum amount of data over the air.  Last but not least, I finish things up with my GetCustomers() method that returns an ObservableCollection of Customer objects to the Windows Phone 7 client.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ContosoWcfService.Models;
using System.Collections.ObjectModel;

namespace ContosoWcfService
{
[ServiceContract]
public interface IRestData
{
[OperationContract]
[WebGet(UriTemplate = “/Customers”, BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
ObservableCollection<Customer> GetCustomers();

    }

}

Service Code

Now it’s time to implement my IRestData Interface with the RestData class.  Inside this class, I have my GetCustomers() method which connects to SQL Server, retrieves a list of Customers and sends it back to Windows Phone 7.  As you can see in the code below, I’m not using the Entity Framework but rather I’m just querying SQL Server directly.  Normally, I would call a stored procedure for even better performance but for clarity I’m showing the actual SELECT statement.  The key to this method is how I create new Customer objects and hydrate them with data as I loop through the SqlDataReader.  I then add them to the ObservableCollection which gets returned to the phone with wireless-friendly JSON encoding.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

using ContosoWcfService.Models;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Collections.ObjectModel;

namespace ContosoWcfService
{
public class RestData : IRestData
{
//Get the Database Connection string
private string _connectionString = WebConfigurationManager.ConnectionStrings[“ContosoBottlingConnectionString”].ConnectionString;

        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;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
_cmd.Dispose();
_cn.Close();
}
}

Web.config

A WCF Service just wouldn’t be complete without a Web.config file.  The big takeway here is I’m storing my connection string to SQL Server and I’ve created a webHttp endpoint behavior for my REST services.  Down in my service name I point to my endpoint behavior, set my binding == webHttpBinding, and set my contract == IRestData.

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>

  <system.web>
<compilation debug=”true” targetFramework=”4.0″ />
</system.web>

  <connectionStrings>
<add name=”ContosoBottlingConnectionString” connectionString=”Data Source=RTIFFANY3\SQLEXPRESS;Initial Catalog=ContosoBottling;Integrated Security=True” providerName=”System.Data.SqlClient” />
</connectionStrings>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
<serviceMetadata httpGetEnabled=”true” />
<!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
<serviceDebug includeExceptionDetailInFaults=”true” />
</behavior>
</serviceBehaviors>

      <endpointBehaviors>
<behavior name=”REST”>
<webHttp />
</behavior>

        <behavior name=”HelpBehavior”>
<webHttp helpEnabled=”true” />
</behavior>

      </endpointBehaviors>

    </behaviors>
<services>
<service name=”ContosoWcfService.RestData”>
<endpoint address=”” behaviorConfiguration=”REST” binding=”webHttpBinding” contract=”ContosoWcfService.IRestData” />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled=”true” />

  </system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests=”true” />
<directoryBrowse enabled=”true” />
</system.webServer>
</configuration>

Conclusion

I hope this helps get you started down the road to building wireless bandwidth efficient WCF Services with REST and JSON.  Keep in mind that you can build these same types of services in Windows Azure as well along with connections to SQL Azure.  In the next article, I’ll show you how to consume these types of services from your Windows Phone 7 project

Keep coding,

Rob

Sharing my knowledge and helping others never stops, so connect with me on my blog at http://robtiffany.com , follow me on Twitter at https://twitter.com/RobTiffany and on LinkedIn at https://www.linkedin.com/in/robtiffany

Sign Up for my Newsletter and get a FREE Chapter of “Mobile Strategies for Business!”

[mc4wp_form id=”5975″]