Z Code

PCL & Azure How-To: Using Portable Class Libraries and AppFabric Service Bus To Create a Continuous Client

Here's how to build a simple continuous client application that spans multiple devices using the cloud Azure to handle communication between the devices.

I feel lucky to live in the days of continuously connected devices. I love that I'm able to reply to e-mail using my phone while riding the bus home. It's amazing to be able to Skype with my family on the other side of the world and team up with like-minded gamers across the country on my Xbox. However, in this world of permanent Internet connectivity, there is, as Joshua Topolsky puts it, "a missing link in our computing experience" (engt.co/9GVeKl). 

This missing link refers to the lack of what Topolsky calls a continuous client; that is, a solution to the broken workflow that occurs today when you move from one device to another. As I switch among my PC, tablet and phone in a typical day, my current browsing session, documents, windows and application state should naturally flow to all of them. That way, I'd spend less time on context switching and more time on actual work and play.

In this article, I'll show you how to build a simple continuous client application that spans multiple devices and platforms. I'll make use of the new Portable Class Libraries (PCLs) to ease the development of a cross-platform application, and the cloud—in particular Windows Azure AppFabric Service Bus—to handle the communication between the devices.

On Your Way Home …
It's late afternoon and I'm at work trying to fix that last bug quickly so I can avoid peak-hour traffic. The inevitable phone call comes: "Honey, on your way home can you pick up some milk, bread and chickpeas?" I hang up, get to the store and realize I've forgotten what to buy. In the end, I head home with items we already have in the pantry. It's frustrating, and today's solution tends to involve a lot of back-and-forth phone calling: "Did you say frozen peas or chickpeas?" "Chickpeas. And while you're there, can you buy toilet paper?"

To help alleviate our marriage tensions around this particular issue (the others will have to wait for another day), I'll write a simple app called "On Your Way Home" that runs on our Windows Phone-based devices and Windows 8 beta tablets and allows my wife and me to easily track our shopping list. It will keep us both informed, in real time, of any changes to the shopping list so that at any time we know exactly what we need to buy.

Given that a smartphone running Window Phone and a Windows 8-based tablet are different devices, with differing flavors of the Microsoft .NET Framework and Windows, I'll use PCLs to abstract away platform differences and enable me to share as much application logic as possible, including all the of the communication with the Windows Azure AppFabric Service Bus. I'll also use the Model-View-ViewModel (MVVM) pattern (bit.ly/GW7l) to facilitate the use of the same Models and ViewModels from our device-specific Views.

Portable Class Libraries
In the past, cross-platform development in the .NET Framework hasn't been easy. While the .NET Framework had grand dreams as a cross-platform runtime, Microsoft hasn't yet fully delivered on the promise. If you've ever attempted to deliver a .NET Framework-based application or framework that spanned multiple devices, you'll have noticed that a few things got in the way.

On the Runtime Side The assembly factoring, versioning and assembly names are different among the .NET platforms. For example, System.Net.dll on the .NET Framework, which contains peer-to-peer networking APIs, means something entirely different on Silverlight, where it contains the core networking stack. To find those APIs on the .NET Framework, you'll need to reference System.dll. The assembly versions are also not the same; Silverlight adopts 2.0.5.0 for versions 2.0 to 4, whereas 2.0.0.0 and 4.0.0.0 were adopted for .NET Framework versions 2.0 to 4. These differences have, in the past, prevented an assembly compiled for one platform from running on another.

On the Visual Studio Side Right from the beginning you need to decide which platform to target—the .NET Framework, Silverlight or Windows Phone. Once that decision is made, it's extremely hard to move to or support a new platform. For example, if you're already targeting the .NET Framework, targeting the .NET Framework and Silverlight means creating a new project and either copying or linking the existing files into that project. If you're lucky, you might have factored your application in such a way that platform-specific pieces are easily replaced. If not (and this is probably more likely), you'll need to #if PLATFORM your way around each build error until you have a clean build.

This is where the new PCLs can help. PCLs, available as a free add-on to Visual Studio 2010 (bit.ly/ekNnsN) and built into Visual Studio 11 beta, provide an easy way to target multiple platforms using a single project. You can create a new PCL, choose the frameworks you'd like to target (see Figure 1) and start writing code. Under the covers, the PCL tools handle the API differences and filter IntelliSense so you see only classes and members that are available and work across all the frameworks you've selected. The resulting assembly can then be referenced and run, without any changes, on all indicated frameworks.

Figure 1. Portable Class Library Target Frameworks

Solution Layout
A typical way to organize a cross-platform app using a PCL is to have one or more portable projects containing the shared components, and have platform-specific projects for each platform that references these projects. For this application, I'll need two Visual Studio solutions—one created in Visual Studio 2010 (OnYourWayHome.VS2010) containing my Windows Phone app and one created in Visual Studio 11 (OnYourWayHome.VS11) containing my Windows Metro-style app. I need multiple solutions because at the time of writing, the Windows Phone SDK 7.1 works only on top of Visual Studio 2010, whereas the new Windows 8 tools are available only as part of Visual Studio 11. There isn't (currently) a single version that supports both. Don't despair, though; a new feature available in Visual Studio 11 helps me out here. I'm able to open most projects created in the earlier version without having to convert them to the new format. This allows me to have a single PCL project and reference it from both solutions.

Figures 2 and 3 show the project layout for my application. OnYour­WayHome.Core, a PCL project, contains the models, view models, common services and platform abstractions. OnYour­WayHome.ServiceBus, also a PCL project, contains portable versions of the APIs that will talk to Windows Azure. Both projects are shared between the Visual Studio 2010 solution and Visual Studio 11. OnYourWayHome.Phone and OnYourWayHome.Metro are platform-specific projects targeting Windows Phone 7.5 and .NET for Metro-style apps, respectively. These contain the device-specific views (such as the pages in the application) and implementations of the abstractions found in OnYourWayHome.Core and OnYourWayHome.ServiceBus.

Figure 2. Windows Phone Project Layout in Visual Studio 2010


Figure 3. Windows Metro-Style App Project Layout in Visual Studio 11

Converting Existing Libraries to PCLs
To communicate with Windows Azure, I downloaded the Silverlight-based REST sample from servicebus.codeplex.com and converted it to a PCL project. Some libraries are easier to convert than others, but you'll inevitably run into situations where a given type or method isn't available. Here are some typical reasons a given API might not be supported in PCLs:

The API Isn't Implemented by All Platforms Traditional .NET Framework file IOs, such as System.IO.File and System.IO.Directory, fall into this bucket. Silverlight and Windows Phone use the System.IO.IsolatedStorage APIs (though different from the .NET Framework version), whereas Windows 8 Metro-style apps use Windows.Storage.

The API Isn't Compatible Across All Platforms Some APIs look and feel the same, but it's hard or impossible to write code against them in a portable and consistent way. ThreadStaticAttribute, which enables static fields to have a unique value for each thread, is an example. Though it's present on both the Windows Phone and Xbox platforms, neither of their runtimes supports it.

The API Is Considered Obsolete or Legacy These APIs either contain behavior that's unlikely to be present on future platforms, or they've been replaced by newer technologies. BackgroundWorker is an example of this; it was replaced by Task and the new asynchronous program features in Visual Studio 11 beta.

We Ran out of Time Most APIs weren't written with portability in mind. We spend a significant amount of time going through each API to make sure it can be programmed against in a portable manner. This might involve tweaking or adding to the API to make it portable. Because of the time and effort involved, in the first version of PCLs we made available on Visual Studio Gallery, we prioritized the high-value, highly used APIs. System.Xml.Linq.dll and System.ComponentModel.DataAnnotations.dll are examples of APIs that weren't available in that first version but are now available in the Visual Studio 11 beta release.

There are a couple of different ways of handling an API that falls into one of these scenarios. Sometimes there's a simple replacement. For example, Close methods (Stream.Close, TextWriter.Close and so forth) have been deprecated in PCL and replaced with Dispose. In such cases, it's just a matter of replacing a call to the former with the latter. But sometimes it's a little harder and takes more work. One situation I encountered while converting the Service Bus APIs involved the HMAC SHA256 hash code provider. It isn't available in a PCL because of the cryptography differences between Windows Phone and Metro-style apps. Windows Phone apps use .NET-based APIs to encrypt, decrypt and hash data, while Metro-style apps use the new native Windows Runtime (WinRT) APIs.

The code in particular that failed to build after the conversion was the following:

using (HMACSHA256 sha256 = new HMACSHA256(issuerSecretBytes))
{
  byte[] signatureBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(token));
  signature = Convert.ToBase64String(signatureBytes);
}

To help bridge the gaps between the Phone crypto APIs and the WinRT crypto APIs, I invented a platform abstraction representing the Service Bus requirement. In this case, the Service Bus needed a way to calculate an HMAC SHA256 hash:

public abstract class ServiceBusAdapter
{
  public static ServiceBusAdapter Current
  {
    get;
    set;
  }
  public abstract byte[] ComputeHmacSha256(byte[] secretKey, byte[] data);
}

I added ServiceBusAdapter to the portable project, as well as a static property for setting the current abstraction, which will become important later. Next, I created Windows Phone- and Windows 8-specific HMAC SHA256 implementations of this abstraction, and put these in their respective projects, as shown in Listing 1.

At startup in the Windows Phone project, I then "bootstrapped" the Service Bus by setting the Phone-specific adapter as the current adapter:

ServiceBusAdapter.Current = new PhoneServiceBusAdapter();

I did the same for the Windows 8 project:

ServiceBusAdapter.Current = new MetroServiceBusAdapter();

With everything in place, I then changed the original non-compiling code to call through the adapter:

var adapter = ServiceBusAdapter.Current;
byte[] signatureBytes = adapter.ComputeHmacSha256(issuerSecretBytes, Encoding.UTF8.GetBytes(token));

So although there are two different ways of computing the hash depending on the platform, the portable project talks to both using a single interface. This can take a little bit of work up front, but I can easily reuse the infrastructure as I run into more APIs that need bridging between the platforms.

As a side note, I used a static property to access and register the adapter, which makes it easier to move existing APIs over to using the adapter. If you're using a dependency injection framework such as the Managed Extensibility Framework (MEF), Unity or Autofac, you'll find that it's natural to register the platform-specific adapter into the container and have the container "inject" the adapter into portable components that need it.

Application Layout
My shopping list application, On Your Way Home, has two simple views: ShoppingListView, which displays the current items on the shopping list; and AddGroceryItemView, which allows a user to add more items to the list. Figures 4 and 5 show the Windows Phone versions of these views.

Figure 4. ShoppingListView


Figure 5. AddGroceryItemView

ShoppingListView shows all the items that are yet to be purchased, with the idea that as you walk around the store, you check off each item as you add it to the cart. After purchasing the items, clicking check out causes the checked items to be taken off the list, indicating they no longer need to be purchased. Devices sharing the same shopping list instantly (well, as instantly as the network behind it allows) see changes made by another person.

The Views, which live in the platform-specific projects, consist mainly of XAML and have very little codebehind, which limits the amount of code you need to duplicate between the two platforms. Using XAML data binding, the Views bind themselves to portable ViewModels that provide the commands and data that run the Views. Because there's no common UI framework that ships across all platforms, PCL projects can't reference UI-specific APIs. However, when targeting frameworks that support them, they can take advantage of APIs that are typically used by ViewModels. This includes the core types that make XAML data binding work, such as INotifyPropertyChanged, ICommand and INotifyCollectionChanged. Also, although the WinRT XAML framework doesn't support them, System.ComponentModel.DataAnnotations and INotifyDataErrorInfo have been added for completeness, and this enables custom XAML validation frameworks to support portable ViewModels/Models.

Listing 2 and 3 show examples of View/ViewModel interactions. Listing 2 shows the controls on the Window Phone version of AddGroceryItemView and their bindings. These controls are bound against the properties on the AddGroceryItemViewModel, which is shared with both the Windows Phone and Windows 8 projects, as shown in Listing 3.

Event Sourcing
On Your Way Home is based heavily around the concept of event sourcing (bit.ly/3SpC9h). This is the idea that all state changes to an application are published and stored as a sequence of events. In this context, event doesn't refer to the thing defined by the C# event keyword (although the idea is the same), but rather to concrete classes that represent a single change to the system. These are published through what's called an event aggregator, which then notifies one or more handlers that do work in response to the event. (For more about event aggregation, see Shawn Wildermuth's article, "Composite Web Apps with Prism," at msdn.microsoft.com/magazine/dd943055.)

For example, the event that represents a grocery item being added to the shopping list looks something like what's shown in Listing 4.

The ItemAddedEvent class contains information about the event: in this case, the name of the grocery item that was added and an ID that's used to uniquely represent the grocery item within a shopping list. Events are also marked with [DataContract], which makes it easier for them to be serialized to disk or sent over the wire.

This event is created and published when the user clicks the add button on the AddGroceryItemView, as shown in Listing 5.

Note that this method doesn't directly make any change to the shopping list; it simply publishes the ItemAddedEvent to the event aggregator. It's the responsibility of one of the event handlers listening to this event to do something with it. In this case, a class called ShoppingList subscribes to and handles the event, as shown in Listing 6.

Every time ItemAddedEvent is published, ShoppingList creates a new GroceryItem using the data from the event and adds it to the shopping list. The ShoppingListView, which is indirectly bound to the same list via its ShoppingListViewModel, is also updated. This means that when the user navigates back to the shopping list page, the items he just added to the list are shown as expected. The process of removing an item from the shopping list, adding an item to a cart and checking out the cart are all handled using the same event publish/subscribe pattern.

It may at first seem like a lot of indirection for something as simple as adding items to a shopping list: the AddGroceryItemViewModel.Add method publishes an event to the IEventAggregator, which passes it onto the ShoppingList, which adds it to the grocery list. Why doesn't the AddGroceryItemViewModel.Add method simply bypass the IEventAggregator and add the new GroceryItem directly to the ShoppingList? I'm glad you asked. The advantage of treating all state changes to the system as events is that it encourages all the individual parts of the application to be very loosely coupled. Because the publisher and subscribers don't know about each other, inserting a new feature in the pipeline, such as syncing data to and from the cloud, is a lot simpler.

Syncing Data to the Cloud
I've covered the basic functionality of the application running on a single device, but there's still the problem of getting the changes a user makes to the shopping list to other devices, and vice versa. This is where the Windows Azure AppFabric Service Bus comes in.

Windows Azure AppFabric Service Bus is a feature that enables applications and services to easily talk with each other over the Internet, avoiding the complexities of navigating communication obstacles such as firewalls and Network Address Translation (NAT) devices. It provides both REST and Windows Communication Foundation (WCF) HTTP endpoints hosted by Windows Azure and sits in between the publisher and the subscriber.

There are three main ways to communicate using the Windows Azure AppFabric Service Bus; for the purposes of my application, however, I'll just cover Topics. For a full overview, check out "An Introduction to the Windows Azure AppFabric Service Bus" at bit.ly/uNVaXG.

For publishers, a Service Bus Topic is akin to a big queue in the cloud (see Figure 6). Completely unaware of who's listening, publishers push messages to the Topic, where they're held ad infinitum until requested by a subscriber. To get messages from the queue, subscribers pull from a Subscription, which filters messages published to the Topic. Subscriptions act like a particular queue, and messages removed from a Subscription will still be seen from other Subscriptions if their own filters include them.


[Click on image for larger view.]
Figure 6. Service Bus Topi

In On Your Way Home, the AzureServiceEventHandler class is the bridge between the application and the Service Bus. Similar to ShoppingList, it also implements IEventHandler<T>, but instead of specific events, AzureServiceEventHandlers can handle them all, as shown in Figure 7.


[Click on image for larger view.]
Figure 7. The AzureServiceEventHandler Clas
public class AzureServiceBusEventHandler : DisposableObject, IEventHandler<IEvent>, IStartupService
{
  private readonly IAzureServiceBus _serviceBus;
  private readonly IAzureEventSerializer _eventSerializer;
  public AzureServiceBusEventHandler(IEventAggregator eventAggregator,
    IAzureServiceBus serviceBus, IAzureEventSerializer eventSerializer)
  {
    _eventAggregator = eventAggregator;
    _eventAggregator.SubscribeAll(this);
    _serviceBus = serviceBus;
    _serviceBus.MessageReceived += OnMessageReceived;
    _eventSerializer = eventSerializer;
  }
  [...]
  public void Handle(IEvent e)
  {
    BrokeredMessage message = _eventSerializer.Serialize(e);
    _serviceBus.Send(message);
  }
}

Every change a user makes to the state of the shopping list is handled by AzureServiceBusEventHandler and pushed directly to the cloud. Neither AddGroceryItemViewModel, which publishes the event, nor ShoppingList, which handles it on the local device, is aware that this happens.

The trip back from the cloud is where an event-based architecture really pays off. When the AzureServiceEventHandler detects that a new message has been received on the Service Bus (via the IAzureServiceBus.MessageReceived C# event), it does the reverse of what it did earlier and deserializes the received message back into an event. From here, it gets published back via the event aggregator, which causes it to be treated as though the event came from within the application, as shown in Listing 7.

The ShoppingList isn't aware (nor does it care) about the source of the event and handles those coming from the Service Bus/cloud as though they came directly from a user's input. It updates its list of groceries, which in turn causes any of the views bound to that list to be updated as well.

If you pay special attention, you might notice one little problem with the workflow: Events that get sent to the cloud from the local device come back to that same device and cause duplication of the data. Worse, changes to other, unrelated shopping lists will also come to that device. I don't know about you, but I'm pretty sure I don't want to see other people's food choices appearing on my shopping list. To prevent this, a Service Bus Topic is created per list, and a Subscription per device, which listens to the Topic. When the messages are published to the Topic from the device, a property containing the device ID is sent along with the messages, which the Subscription filter uses to exclude messages that came from its own device. Figure 8 shows this workflow.


[Click on image for larger view.]
Figure 8. Device-to-Device Workflow

Wrapping Up
I covered a lot in this article: Portable Class Libraries simplified my solution and significantly reduced the amount of code I needed to write to target the two platforms. Also, changing application state via events made it very easy to sync that state with the cloud. There's still a lot I've left unsaid, however, that you'll want to factor in when developing a continuous client. I didn't talk about offline event caching and fault tolerance (what if the network isn't available when I publish an event?), merge conflicts (what if another user makes a change that conflicts with mine?), playback (if I attach a new device to the shopping list, how does it get updated?), access control (how do I prevent unauthorized users accessing data they shouldn't?) and finally, persistence. In the sample code for the article, the application doesn't save the shopping list between launches. I'll leave this as an exercise for you; it might be an interesting challenge if you want to play around with the code. A naïve (or rather the traditional) way of approaching persistence might be to a put a hook directly into the ShoppingList class, mark the GroceryItem objects as serializable and save them off to a file. Before going down this route, though, stop and think about it: Given that the ShoppingList already handles events natively and already doesn't care where they come from, syncing data to and from the cloud looks surprisingly like saving and restoring data from disk, doesn't it?

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube