Geeks With Blogs

News
Joe Mayo Cloud and Glue

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:

#if SILVERLIGHT
            WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
            WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
#endif

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
            if (!Application.Current.IsRunningOutOfBrowser)
            {
                ProxyUrl =
                        Application.Current.Host.Source.Scheme + "://" +
                        Application.Current.Host.Source.Host + ":" +
                        Application.Current.Host.Source.Port + "/LinqToTwitterProxy.ashx?url="; 
            }
#else
            ProxyUrl = string.Empty;
#endif

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);
#else
            var array = dictionary.GetValue<ArrayList>(key, null);
#endif

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:

#if NETFX_CORE
                                            Task.Delay(errorWait);
#else
                                            Thread.Sleep(errorWait);
#endif

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.

Summary

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.

@JoeMayo

Posted on Friday, May 11, 2012 8:33 AM C# | Back to top


Comments on this post: Pre-Processing Directives for Multi-Platform Support

# re: Pre-Processing Directives for Multi-Platform Support
Requesting Gravatar...
Strictly, they're not pre-processor directives because there is no pre-processor. C# is a single pass compiler. They're conditional compilation directives.
Left by Steve 'Sly' Williams on May 14, 2012 9:24 AM

# re: Pre-Processing Directives for Multi-Platform Support
Requesting Gravatar...
Thank you for your kind information it really help me out in my difficulties i am waiting for your next informative post. thank you
Left by beauty tips on May 16, 2012 11:47 AM

# re: Pre-Processing Directives for Multi-Platform Support
Requesting Gravatar...
Steve, I see what you're saying and in some sense an argument can be made for your perspective. The fact is that the C# Specification, which you can read at http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=7029, defines them as Pre-processing directives. The spec does acknowledge the C and C++ lineage for the term and explains the point you're trying to make, but it clearly indicates that the terminology I'm using is correct.
Left by Joe Mayo on May 22, 2012 8:29 PM

Your comment:
 (will show your gravatar)
 


Copyright © Joe Mayo | Powered by: GeeksWithBlogs.net | Join free