A true cross-platform .NET library (part 1)

A true cross-platform .NET library (part 1)

.NET was designed to be cross-language and cross-platform. Unfortunately along its history, Microsoft decided to fork it into subsets, starting with Silverlight and Windows Phone 8. The CLR also changed from .NET 3.5 to .NET 4.0. A single assembly solution no longer works for all .NET flavors.

I recently released a small open-source library and wanted to make it available on as many .NET flavors as possible, including Xamarin, Unity and .NET Micro Framework.

NOTE: .NET Platform Standard is an open-source effort by Microsoft to fix the subsets issue but Xamarin and Unity will take time to adopt the new framework. Still, I don’t believe it will ever consider .NET Micro Framework.

Portable Class Library

A PCL project generates an assembly that complies with multiple .NET flavors. Visual Studio has a dialog in the project settings where we can check the flavors we want to target.

pcl

As each flavor is a subset of .NET, the more flavors we add, the less features we may have available. My small project doesn’t have any specific dependency so it wasn’t an issue but it may be for more complex projects. If you run into problems, I suggest this other post by Daniel Plaisted.

To easily deploy into projects, we can package the assembly into a nuget package. To create one of these packages we need to specify in the .nuspec file the supported platforms in the form of folders. The name of the folder for a PCL assembly can be quite complex. For more info check this other post. For Xamarin NuGet support, I had to open one of their packages using NuGet Package Explorer and check what folder structure they use.

We should be done by now. Unfortunately that’s not really true…

Unity

Unity‘s script engine is built on top of CLR 2.0, meaning it supports .NET up to version 3.5. As you can see from the next image, PCL only supports .NET 4 and up. There is no PCL support for Unity. 😦

pcl2

To target Unity, we need to add a new ‘class library’ project to the solution. Use a ‘.Net35’ sufix on the name to make it easier to find. In the project settings, set the ‘target framework’ to ‘.NET Framework 3.5 Client Profile’. The assembly name doesn’t need to have the platform sufix as it will not conflict with others later. NuGet will only install the assembly specific to the project traget platform.

NOTE: If you have code that depends on UnityEngine.dll or UnityEditor.dll, my suggestion is to add a ‘class library’ for each, with ‘.Unity’ or ‘.UnityEditor’ sufixes, that also targets ‘.NET Framework 3.5 Client Profile’. Don’t forget to place the ‘.UnityEditor’ assembly in a ‘Editor’ folder so that it’s not shipped with the application runtime.

We now need to share the source code between the PCL and .NET 3.5 projects. The best way to do this is to add a new ‘shared project’ to the solution. Use ‘.Shared’ at the end of the project name to make it also easier to find. Move the .cs source files into this project. This new project can then be added as a reference in the other projects and its content is compiled as if it was inside these other projects.

shared

The resulting assembly can be added to the previous NuGet package but into the ‘lib/net35’ folder.

Unfortunately Unity does not support NuGet. It uses its own Asset Package format. To create one of these packages, we need to open Unity,  add the assembly to the Unity project’s ‘Assets’ folder and then click on ‘Export Package…’ under the ‘Assets’ menu item. We can distribute this package as is and/or make it available at the Unity Asset Store.

.NET Micro Framework

On my free time I like to play with micro-controllers. I’ve been using boards like the Netduino and the FEZ Cerbuino Bee. They support .NET Micro Framework and I like to use my .NET libraries in these projects too.

To develop for this platform we need to install the framework and the Visual Studio extension available at https://github.com/NETMF/netmf-interpreter/releases.

.NET Micro Framework SDK 4.3 and older are available at https://netmf.codeplex.com/releases/view/611040 under ‘SDK MSI’. You don’t need to install the Visual Studio extensions from here if you are already using the extension for Visual Studio 2015.

If you use AppVeyor for continuous integration, you can use these PowerShell scripts to add support for .NET Micro Framework builds.

We now need to add a new ‘Class Library’ project from the ‘Micro Framework’ category.

netmf

We can set the target framework version in the project settings once it’s created. This means we need one project for each targeted version. Name the projects with sufixes like ‘.NetMF42’, ‘.NetMF43’ and ‘.NetMF44’ so that the version is easy to spot.

netmf2

The .cs source code has to added to these new projects. Unfortunately .NET MF projects do not support shared projects.

shared2

We’ll have to use the old-fashioned solution by adding the source files as links. It’s available in the ‘Add Existing Item…’ dialog as a drop-down of the ‘Add’ button.

addaslink

The resulting assemblies can then be added to the previous NuGet package into the ‘lib/netmf43’, ‘lib/netmf43’ and ‘lib/netmf44’ folders respectively. Note that the  folders ‘be’ and ‘le’ and the assemblies in them also have to be added to the package.

Conclusion

If you want to really support multiple .NET flavors, a PCL or a shared project may not be the ‘one size fits all’ solution but with some work you can create a single NuGet package that targets most .NET flavors. Some call this the “bait and switch PCL trick“.

Clone NetFabric.Angle for a sample of the project structure described in this post.

Now, go to part 2 on how to manage platform-specif code.

 

 

Advertisements