NuGet Package Alternatives when Migrating to .NET Core

NuGet Package Alternatives

Migrating from .NET Framework to .NET Core requires all of your NuGet Package dependencies to also be compliant with .NET Core. But what happens when you find a dependency that only targets .NET Framework? Here are a few NuGet package alternatives that I’ve run into during 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:

Entity Framework

Probably the most common dependency most projects have is on Entity Framework. Luckily there are a few options in terms of support for .NET Core.

First, Entity Framework version 6.3 and higher target .NET Standard 2.1. Which means that you must migrate to .NET Core 3.0 or higher.

This is a bit of a problem if you want to migrate to .NET Core 2.1 as I’ve mentioned in my previous posts. This is more applicable if you’re migrating from ASP.NET on .NET Framework.

There is a second option which is to use Z.EntityFramework.Classic

Entity Framework Classic is an EF6 fork with performance enhancement, new features, and .NET Core support.

The community (free) version supports everything that’s in EF6 but targets .NET Standard 2.0. Which means you can run on .NET Core 2.1.

Machine Key

If you’re using System.Web.MachineKey and cannot for whatever reason move to the new ASP.NET Core Data Protection, you might want to look at AspNetCore.DataProtection.MachineKey

This package adds a new DataProtector that is configured using your existing Decryption & Validation Keys from your web.config. This allows you to Decrypt data that you might have already encrypted using MachineKey on .NET Framework. This package also supports .NET Standard 2.0


If you do any image processing on .NET Framework, you might be using the ImageProcessor library. Although not a direct replacement, the same author, James Jackson-South has created a new library ImageSharp that does work on .NET Core

These libraries are completely different. ImageSharp is not a drop in replacement for ImageProcessor but it’s by far the best image library that can run on .NET Core.


Another issue we ran into was PDF generation. For this I turned to IronPDF. This is a commercial product that requires a license. It does support .NET Standard 2.0 and works on Windows, MacOS, and Linux.

If you’re using PdfSharp, there is a ┬áreplacement package, PdfSharpCore.PdfSharp that targets .NET Standard.

NuGet Package Alternatives

Have you run into packages that don’t support .NET Core or .NET Standard?

If you have and/or have found any NuGet package alternatives, let me know in the comments or on Twitter. I’d like to keep this an evolving post with other recommendations.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Multi-Targeted NuGet Package Gotchas!

Multi-Targeted NuGet Package Gotchas!

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:


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 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.

.NET Framework Output

.NET Core Output

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.

.NET Framework
.NET Standard

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.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

CAP: Event Bus & Outbox Pattern

Outbox Pattern

If you’re thinking of building or already are implementing a system using async messaging (SOA or Microservices) then you need to start thinking about what type of messaging library you want to use in front of a message broker. CAP is an Event Bus that implements the Outbox Pattern to deal with distributed transactions.


I did a live stream exploring CAP that is over on my YouTube Channel.

Distributed Transaction

When you’re using messages (events) to communicate between systems you will run into the situation where you need to save data to your database, then publish an event to a message broker. These events will then be received up by other systems for their own internal use.

The problem arises when two situations occur:

  • You save data to your database but there is a failure when publishing the event to your message broker
  • You publish an event to your message broker that something occurred in your system, but then when trying to save to your database, it fails.

In both situations, there is no consistency between what your database has saved and what you have published to the message broker.

What you want in this situation is one atomic transaction that can save data to your database and publish the event. If either fails, the other is rolled back. Basically, a distributed transaction.

Outbox Pattern

The Outbox pattern solves this issue by using a single transaction to perform both actions. What this involves is rather than publishing the event directly to the message broker, it serializes the event and saves it to a table in the same database using the same transaction for persisting your application data.

This is a diagram of the outbox pattern described in Microsoft’s eShopOnContainers reference application

Outbox Pattern

Once the event is persisted to the table within the database, it will then be published to the message broker. If the message broker is unavailable or there is a failure publish to the message broker, the library you’re using will retry to publish. It provides reliability that you are not losing messages that you need to publish.


I stumbled upon the CAP project as I was looking for references for how other libraries have implemented the outbox pattern.

The following just illustrates the simplicity of using the CAP library and it’s API. My example uses MySQL as the database and RabbitMQ as the message broker.

First step is to include the relevant packages to your project

Next is to configure the Startup. In the ConfigureServices we need to use the AppCap() with various options to configure our database and message broker connections. Also in the Configure I’ve added the UseCapDashboard() which provides a little web-based UI for showing the messages and event subscriptions.

Now that we have CAP configured, the first step is going to be publishing an event. You do this by using the ICapPublisher. The parameters are a name and the contents of the event.

The key thing to point out here is that BeginTransaction() is an extension method from CAP. This extension method starts the MySQL transaction but also passes it along to the CapPublisher so they are using the same transaction. CapPublisher needs this transaction because it is going to write the published events to a table within your database.

CAP automatically creates this table. There is no setup required on your end.

Finally, we can create a subscriber/receiver for this event. To do so is simply a matter of implementing ICapSubscribe and add the CapSubscribe attribute to a method with the appropriate arguments that match what was published.

That’s it!

That’s the simplest example. And it’s pretty simple and hopefully gives you an idea of how CAP works with implementing the outbox pattern. There are various message brokers it supports such as Kafka, RabbitMQ, and Azure Service Bus. On the database side it supports SQL Server, MySQL, PostgreSQL, and MongoDB.

My entire sample application is available on GitHub.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.