Dismissile Dismissile - 3 months ago 19
C# Question

Multiple platform projects and NuGet

I have created a library that I need to be able to use in a Portable Class Library as well as a regular .NET application. The way I accomplished this is by creating multiple solutions / projects that point to the same files:

Src/
Dismissile.sln
Dismissile.Portable.sln
Dismissile/
Dismissile.csproj
Dismissile.Portable.csproj
Class1.cs


Dismissile.sln includes Dismissile.csproj and targets .NET Framework 4.5.2
Dismissile.Portable.sln includes Dismissile.Portable.csproj and is a portable class library project that targets .NET Framework 4.5, Xamarin.Android and Xamarin.iOS.

Each project includes Class1.cs. I have created some conditional compilation symbols in each project such as PORTABLE and NET452.

This seems to work so fine but now I need to add a NuGet package for JSON.NET into my projects.

If I add a NuGet package in my Portable project it will create the following in my packages.config:

<package id="Newtonsoft.Json" version="9.0.1" targetFramework="portable40-net40+sl5+win8+wp8+wpa81" />


However, if I add it in my other project it will create the following in packages.config:

<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />


Is there any way to have a separate packages.config so each project includes the correct reference to my NuGet dependencies?

Answer

The easiest solution for this scenario is to create distinct folders for every project and include the .cs-files via a link. (see MSDN - Add as Link)

Doing so enables you to reference different packages (and versions) for different platforms (projects), as you have distinct packages.config-files.

Additionally, I should mention that you may encounter incompatible framework methods (such as Task.Factory.StartNew for NET40 and Task.Run for NET45), which can be solved in two different ways:

Working with compiler constants

Define a framework contstant in your projects, and query them with preprocessor-directives, like:

#if NET40
Task.Factory.StartNew(...)
#elif NET45
Task.Run(...)
#endif

Working with partial classes and methods

Dismissile.NET40\FooClass.cs

public partial class Foo
{
  public void Bar()
  {
    // ...
    this.RunTask(task);
  }

  partial void RunTask(Task task);
}

Dismissile.NET40\Partial.FooClass.cs

public partial class Foo
{
  partial RunTask(Task task)
  {
    Task.Factory.StartNew(task);
  }
}

Dismissile.NET45\Partial.FooClass.cs

public partial class Foo
{
  partial RunTask(Task task)
  {
    Task.Run(task);
  }
}

Summary

My preferred solution is partial classes and methods, as they don't mess up your source with nestings (due to #if-statements), stepping while debugging is way more natural, and finally this approach is more flexible for complicated scenarios.