Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
In order to migrate your application from .NET Framework to .NET Core, one part of the migration is making sure all of your dependencies via NuGet packages will work on .NET Core. Most packages nowadays are multi-targeted. Meaning they target various versions of .NET Framework, .NET Core, and .NET Standard. Here are a few of multi-targeted NuGet package gotchas that I’ve discovered in my own migration.
Migrating from .NET Framework to .NET Core
This post is in a blog series for migrating from .NET Framework to .NET Core. Here’ are some earlier post if you need to catch up:
- Migrating from .NET Framework to .NET Core Overview
- Migrating to ASP.NET Core
- .NET Portability Analyzer
- NuGet Package Alternatives when Migrating to .NET Core
- Mission Complete
Check out my YouTube channel where I also cover this topic
Before we get into the gotchas, I want to just clarify that in your migration from .NET Framework to .NET Core, you need to look at all of your NuGet Packages that you depend on, and confirm they are targeting .NET Core or .NET Standard.
The simplest way to do this is to go to nuget.org and do a search for your package. Here’s an example of Newtonsoft.Json
Under the dependencies section, it lists each platform it targets as well as the dependencies it needs when running under that platform. The thing to be on the look out for is .NET Standard 2.0 (or lower) or .NET Core. It should list .NET Framework as you’re already using it under that if you’re attempting to migrate.
This is what multi-targeting. This package is built for various targets and the NuGet package you download contains the assemblies for each of these targets. When you build your project, the appropriate assembly is used depending on which platform you’re running under.
Gotcha #1: Behavior
It would be fair to assume that the package you use would behave the same under .NET Framework or .NET Core. However, that’s not always the case. Library authors will use #if directives to have certain code only exists when built when targeting a certain platform. Because of this, there may be differences in behavior when you run the exact same code on .NET Framework or .NET Core.
An example of this that I ran into was with NodaTime. When serializing a ZonedDateTime object to JSON via JSON.NET, the output was different.
Thankfully this issue was resolved in the 3.0 release of NodaTime. It now consistently uses the same serialization regardless of target. However, this still proves that there may be differences in behavior that you may not expect.
Gotcha #2: API Surface
Just because you’re using the same version of a NuGet package against .NET Framework and .NET Core does not mean that each target has the same API surface. Just like gotcha #1, this is also because of #if directives. Meaning, library authors may leave out APIs for certain targets.
An example of this is with the AWS SDK. Specifically the AWS S3 Package.
If you’re using this package with .NET Framework, there are non-Async APIs such as the GetObject method on the AmazonS3Client. However, once you’re targeting .NET Core it uses the .NET Standard target which does not contain any sync methods. Instead, they are all marked as internal. This means that you will not be able to even build your project when you target .NET Core.
Gotcha #3: Serializing BCL Types
This last gotcha isn’t so much with NuGet packages, but more so with JSON.NET and serializing standard types that are in the Bass Class Library.
This is very specific when you’re using JSON.NET and serializing/deserializing with TypeNameHandling.All. This setting adds type information to the JSON output from SerializeObject so that you can use it later when deserializing.
The problem is that BCL types live in different assemblies. In .NET Framework this is referred to as mscorlib. In .NET Core it’s System.Private.CoreLib.
When you serialize a List<string> here is the output in .NET Framework:
Output from .NET Core:
If you try and deserialize the .NET Core output when running on .NET Framework it will throw a JsonSerializationException.
This is something to be aware of if during your migration you’re communicating between services/applications that are mixed between .NET Framework and .NET Core.
Multi-Targeted NuGet Package Gotchas
If you’ve run int other gotchas during a migration, let me know in the comments or on Twitter.