Multi Targeting
Tags: csharp, dotnet, visualstudio
Published: 2019-03-07 04:54:39

---
title: Multi Targeting
published: true
description: I recently decided to try to make Couchbase Lite .NET a multi target project.  There are a lot of things that can go wrong, so I will try to compile up to date information.
tags: csharp, dotnet, visualstudio
---

Couchbase Lite .NET runs in a lot of different places, that means:

- .NET Framework on Windows
- .NET Core on Mac, Windows, Linux
- Xamarin iOS
- Xamarin Android
- UWP

Currently, the structure is that the entire library is a .NET Standard 2.0 library with some platform specific features provided via dependency injection.  However, there have been some kinks with this approach, so I decided to take a look at what I would have to do in order to make it a multi target project instead.

First I will start off with a definition of what multi targeting is.  Until recently, every .NET project has been based off of a certain runtime such as .NET Framework, or Xamarin iOS and the artifacts are for that runtime.  .NET Standard was introduced as a way to provide one fake runtime that actually ran on a bunch of different ones but this takes things one step further.  Instead of one target framework, the project will target many and during compile it will compile outputs for each one of them.  So if you had .NET Framework *and* Xamarin iOS, you would get both outputs from one project.

Does this sound like the old PCL days?  Well that seems to be where it got its cue from.  Back in the PCL days, library authors would use a trick called "bait and switch" in which they wrote a shell interface to be reference via the portable library and relied on an implementation detail of NuGet that would cause it to choose the most specific implementation for a given runtime.  That way, if a "portable" and ".NET Framework" version were in the same package, .NET Framework would prefer the latter variant.  If a non-supported platform came along then it would simply throw exceptions on that platform since that was what was actually being generated in the "bait" assembly. 

This approach was pretty well received and has now pretty much become official.  The multi target project is a tool to help with this in that it can generate many platforms at once to package into a NuGet package.  So let's get into exactly what it takes to get started.

STEP ONE:  Create a `global.json` file next to your solution.  The contents will be as follows.  The version should be whatever highest version is available (which at the time of writing is 1.6.68):

```javascript
{
    "msbuild-sdks": {
        "MSBuild.Sdk.Extras": "1.6.68"
    }
}

```

This step enables you to create a new project type that adds onto the current .NET Core SDK.  This is needed because .NET Core does not, and may not ever, support Xamarin, UWP, and others out of the box.  This SDK was written by [Oren Novotny](https://rd.microsoft.com/en-us/oren-novotny) who authors many things that are amazing in the .NET universe so you can trust that it won't just fade away.

STEP TWO:  With that in place, you need to hand edit your `.csproj` file to use this SDK instead of the default one.  Just replace the first line

```xml

<Project Sdk="Microsoft.NET.Sdk">
```

with

```xml
<Project Sdk="MSBuild.Sdk.Extras">
```

STEP THREE:  The final step, find your `<TargetFramework>` entry, and change it to a semicolon separated `<TargetFrameworks>` entry (plural).  For example

```xml
<TargetFramework>netstandard2.0</TargetFramework>
```

becomes


```xml
 <TargetFrameworks>netstandard2.0;netcoreapp2.0;net461;uap10.0.16299;MonoAndroid80;Xamarin.iOS10</TargetFrameworks>

```

That's it!  Now when you compile, you will find that your bin/Debug or bin/Release folder will contain several entries, one for each of the frameworks you are targeting.  You can even use platform specific code, but you need to either only include it when compiling for the framework that supports those functions (more advanced and outside the scope of this article) or guard the source with `#if` blocks.  As a hint, the above definitions will be automatically added for each of the target frameworks in order:

- `NETSTANDARD2_0` and `NETSTANDARD`
- `NETCOREAPP2_0` and `NETCOREAPP`
- `NETFRAMEWORK` and `NET461`
- `UAP_10_0_16299`
- `__ANDROID__` and a ton of android API level specific androids
- `__IOS__`

Happy cross platforming!