Over the last several months, I’ve been modifying LINQ to Twitter to support multiple platforms. Originally, I had targeted full profile .NET, ASP.NET Web Forms, and ASP.NET MVC apps. An easy stop along the way was Mono compatibility, but that was simple because Mono is good about running any CLR app. The code-base was good until I started porting to Silverlight.
Porting to Silverlight
Silverlight requires a different type of class library, so right-away I couldn’t use the same libraries as the full profile version. To fix this, I moved the physical files over to the Silverlight library and tried to compile. This didn’t work because certain .NET libraries were either not present, missing features, or required additional code in Silverlight. I didn’t want to maintain two separate code bases, so I left the physical files in the Silverlight project and created file links from the full profile library to the Silverlight files. To create file links, I right-clicked the folder, selected Add Existing Files, and navigated to and selected the files. Instead of clicking the Add button, there’s a drop-down arrow on the right side of the Add button, which has an option named Add As Link, which I selected. This still doesn’t fix the problem with differences in libraries.
To account for the differences in libraries, I used pre-processing directives. Silverlight has a defined SILVERLIGHT symbol, that ships with the default project template, which is what I used. Here’s an example of how I used it:
The example above demonstrates a Silverlight-only scenario requiring registration of prefixes for HTTP communication. It uses #if and #endif to block off code that will only compile in the Silverlight project, which defines the SILVERLIGHT symbol.
A natural consequence of this strategy is that you only want to use a symbol that is unique to a specific project type if the logic only pertains to that project type. However, sometimes the lines blur. After porting to Silverlight, I went on to create a Windows Phone version of LINQ to Twitter.
Porting to Windows Phone
Since Windows Phone uses Silverlight, I was tempted to use the same define symbol, but that wouldn’t be good because there are situations, like the example above that are unique to Silverlight Web Applications, but not Silverlight for Windows Phone. Fortunately, Windows Phone has a default WINDOWS_PHONE symbol that ships with its templates. Here’s an example for a Silverlight scenario that doesn’t work for Windows Phone:
#if SILVERLIGHT && !WINDOWS_PHONE
Application.Current.Host.Source.Scheme + "://" +
Application.Current.Host.Source.Host + ":" +
Application.Current.Host.Source.Port + "/LinqToTwitterProxy.ashx?url=";
ProxyUrl = string.Empty;
In the example above, Silverlight Web Apps require a proxy, but Windows Phone doesn’t. This results in a more sophisticated condition that excludes Windows Phone’s from being configured with a proxy. Notice the AND and NOT operators and the #else clause for refining this condition.
Porting to Client Profile
After supporting Silverlight and Windows Phone, I turned my attention to a recurring problem that I saw happening. It seems that people would try out LINQ to Twitter by starting a new Console app and running a simple query. The problem is that it wasn’t so simple because the default profile of a Console application is Client Profile. The conflict occurs because LINQ to Twitter supports ASP.NET Web Forms and MVC, whose libraries are not included in Client Profile. This prevented the application from building. Most people figured out that they could move forward by opening Properties and and switching the Target framework to one of the non-Client Profile options, but the situation did highlight the usefulness of supporting Client Profile.
Client Profile doesn’t have any default defined symbols, so I created one for the new library named CLIENT_PROFILE. At first, this was very useful because I learned that Client Profile doesn’t include any of the JSON serialization libraries that I was using. Fortunately, I had recently integrated LitJson into LINQ to Twitter, which I could use with the Client Profile library. Here’s an example:
#if SILVERLIGHT || CLIENT_PROFILE
var array = dictionary.GetValue<list<object>>(key, null);
var array = dictionary.GetValue<ArrayList>(key, null);
The example above uses the OR operator in the pre-processing directive to indicate that both Silverlight and Client Profile need the same code – operating on a generic List<object> because ArrayList isn’t part of their profiles.
Porting to Windows 8
Most recently, I ported LINQ to Twitter to support Windows 8 Metro Style Class Libraries. The template for Windows 8 libraries ships in Visual Studio 11 and defines the NETFX_CORE symbol. There are a few significant library changes that I had to account for, but making the code work on multiple platforms, including Windows 8 is doable. Here’s one example:
In Windows 8, you use the Task Parallel library (TPL), instead of the Thread class and other .NET libraries. Since LINQ to Twitter supports .NET 3.5, but Microsoft doesn’t officially support TPL for .NET 3.5, the Thread class is still necessary. I encountered more scenarios with various types, reflection, and collections that needed special handling with pre-processing directives, all of which were handled similar to the examples you’ve seen so far. Moving the code between Visual Studio 11 and Visual Studio 2010 was seamless because I didn’t change the Target frameworks on any of the other class library types.
Note: You can view the LINQ to Twitter Source Code on CodePlex to see what my check-ins looked like today (5/10/12) to see how I made the LinqToTwitterRT library changes and merged with the existing code base.
Porting class libraries to different .NET platforms isn’t always easy. Each platform adds and removes features that are appropriate in their own context. My approach was to have a common set of physical files, link to those files from other projects, and then use pre-processing directives to manage the differences. You saw examples of how I did this by porting to Silverlight, Windows Phone, Client Profile, and finally Windows 8. As you can see the code gets a bit fragmented at times, but it isn’t too bad, and most importantly, it works.