Writing Portable Code

With so many different incarnations of the .NET Framework, targeting multiple versions and profiles can get tricky.  Ideally, it should be possible to share a common set of code across multiple platforms without the need to create multiple projects, each targeted to a different version.  Until now you had you alternatives: (1) store common code in a lower version assembly and reference it from higher version assemblies, or (2) use linked files between assemblies.

With my Simple MVVM Toolkit, I took the second approach, placing common code in a source project, and then linking to those files from platform-specific projects, such as Silverlight, WPF or Windows Phone. To accomplish this, I simply added an existing item to the target project, but instead of clicking the Add button, I selected the Add As Link button.

add-shared-link.jpg

Although the physical class file resides in the source project, it is pulled into the assembly of the target project when it is built, compliments of an MSBuild task.  You can even insert preprocessor directives in the source file to include code that is platform-specific.

public class DotNetClass { public string GetInfo() { #if SILVERLIGHT return "I am a Silverlight class."; #else return "I am a .NET class."; #endif } }

While this approach gets the job done, it has its drawbacks, the main one being that a different project for each target platform must be created, which can proliferate to include numerous profiles, for example, the .NET client profile, Silverlight and Windows Phone. It would be nice if you only had to maintain a single project that could be referenced by a number of different targets, as well as flavors of .NET that are new on the scene, such as Windows 8 and Windows RT, or ones that haven’t even emerged yet.  To address this challenge, Microsoft released the Portable Class Library project type for Visual Studio 2012 (there is a separate download for Visual Studio 2010).

Feature .NET Framework Windows Store Silverlight Windows Phone
Core
LINQ
IQueryable Only 7.5
Dynamic Only 4.5  
MEF  
Network
Serialization
WCF
MVVM Only 4.5
Data Annotations Only 4.0.3, 4.5  
LINQ to XML Only 4.0.3, 4.5
Numerics  

This table represents which features are supported for each target platform.  XBox 360 can also be targeted, but then you’re limited to Core and LINQ to XML only.  When adding a portable class library project, you select which flavors of .NET you would like to support and consequently which features of .NET can be used in your common code, but you can always change this later via the Library tab of the project properties page.  The resulting DLL can be referenced by any of the selected target frameworks.

add-pcl

Jeremy Likness has a three-part series on how a portable class library uses type forwarders so that the correct type is surfaced to the target platform when an assembly references a portable library.  Check it out to see how things work under the covers.

Once you’ve decided to convert your common code to a portable class library, you need a way to wire up code that is platform-specific.  With linked files all you have to do is include necessary preprocessor directives, but that won’t work if you’re using PCL’s.  This was a significant roadblock when it came to refactoring my MVVM toolkit to use a portable library.  The ViewModelBase class uses a Dispatcher from System.Windows.Threading, which is set to either Dispatcher.CurrentDispatcher for WPF or Deployment.Current.Dispatcher for Silverlight.  The main problem is that the base Dispatcher class is not included in the available portable API’s.

At first I considered programming against SynchronizationContext to handle situations where a call starts on a non-UI thread and needs to be marshaled onto the UI thread.  But the API is different and would have introduced breaking changes into the code base.  So instead I opted for an IDispatcher interface to abstract away the Windows Dispatcher in WPF and Silverlight.  It contains two methods: CheckAccess and BeginInvoke.

public interface IDispatcher { bool CheckAccess(); void BeginInvoke(Action action); }

Then in a ViewModelBaseCore abstract base class I inserted a protected constructor accepting an IDispatcher argument, and I added the class to the shared PCL project.

public abstract class ViewModelBaseCore<TViewModel> : INotifyPropertyChanged { protected readonly IDispatcher Dispatcher; protected ViewModelBaseCore(IDispatcher dispatcher) { Dispatcher = dispatcher; } }

In the target-specific project, I invoked the protected ctor, passing in the implementation of IDispatcher corresponding to the target platform (Silverlight or WPF).

public abstract class ViewModelBase<TViewModel> : ViewModelBaseCore<TViewModel>, INotifyDataErrorInfo { protected ViewModelBase() : base(UIDispatcher.Current) { } }

UIDispatcher is basically a singleton, with a Current property that returns the appropriate implementation using good old fashioned linked files and preprocessor directives.

public static IDispatcher Current { get { #if SILVERLIGHT WindowsDispatcher windowsDispatcher = Deployment.Current.Dispatcher; #else WindowsDispatcher windowsDispatcher = WindowsDispatcher.CurrentDispatcher; #endif _dispatcher = new UIDispatcher(windowsDispatcher); return _dispatcher; } }

One way to distribute portable code is via the NuGet Package Manager that comes pre-installed as an extension in Visual Studio 2012.  There is special support built into NuGet for portable class libraries.  A visual tool is available for building packages, but in the past I’ve always used the command-line tool.  Basically, you have to create a lib folder, then within that folder, you create subfolders for each target platform, for example, net45, sl5, wp71, windows8.  But as of NuGet version 2.1, you can instead create a portable class library and place it in a folder name starting with portable- and followed by a list of platforms, delimited by the + sign.  For example: portable-net45+sl5+wp71+windows8.  This works wonderfully, and it enables you to place binaries in just this one folder, instead of having separate folders for each target platform.

However, if you have both a portable library and a platform-specific library (as is the case with v4 of my Simple MVVM Toolkit), then NuGet will ignore the portable folder and just use the platform-specific folder, so you’re better off just having the platform subfolders, each containing both the portable library and the platform-specific library.

In summary, the Portable Class Library tools are a great way to share code across multiple versions and profiles of the .NET Framework, but you’re limited to code that will run across all the target platforms you specified for your portable library.  So if you want to include functionality that differs from one platform to the next, such as UI cross-threading capability, you’ll also need to build platform-specific assemblies which can reference the common assembly.  Deploying portable code is made easier by NuGet, which has built-in support for portable class libraries.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s