How to reference a .NET Core library in WinForms - Or, .NET Standard Explained
I got an interesting email today. The author said "I have a problem consuming a .net core class library in a winforms project and can't seem to find a solution." This was interesting for a few reasons. First, it's solvable, second, it's common, and third, it's a good opportunity to clear a few things up with a good example.
To start, I emailed back with "precision questioning." I needed to assert my assumptions and get a few very specific details to make sure this was, in fact, possible. I said. "What library are you trying to use? What versions of each side (core and winforms)? What VS version?"
The answer was "I am working with VS2017. The class library is on NETCoreApp 1.1 and the app is a Winforms project on .NET Framework 4.6.2."
Cool! Let's solve it.
Referencing a .NET Core library from WinForms (running .NET Full Framework)
Before we parse this question. Let's level-set.
.NET is this big name. It's the name for the whole ecosystem, but it's overloaded in such a way that someone can say "I'm using .NET" and you only have a general idea of what that means. Are you using it on mobile? in docker? on windows?
Let's consider that ".NET" as a name is overloaded and note that there are a few "instances of .NET"
- .NET (full) Framework - Ships with Windows. Runs ASP.NET, WPF, WinForms, and a TON of apps on Windows. Lots of businesses depend on it and have for a decade. Super powerful. Non-technical parent maybe downloads it if they want to run paint.net or a game.
- .NET Core - Small, fast, open source, and cross-platform. Runs not only on Windows but also Mac and a dozen flavors of Linux.
- Xamarin/Mono/Unity - The .NET that makes it possible to write apps in C# or F# and run them on everything from an iPad to cheap Android phone to a Nintendo Switch.
All of these runtimes are .NET. If you learn C# or F# or VB, you're a .NET Programmer. If you do a little research and google around you can write code for Windows, Mac, Linux, Xbox, Playstation, Raspberry Pi, Android, iOS, and on and on. You can run apps on Azure, GCP, AWS - anywhere.
What's .NET Standard?
.NET Standard isn't a runtime. It's not something you can install. It's not an "instance of .NET." .NET Standard is an interface - a versioned list of APIs that you can call. Each newer version of .NET Standard adds more APIs but leaves older platforms/operating systems behind.
The runtimes then implement this standard. If someone comes out with a new .NET that runs on a device I've never heard of, BUT it "implements .NET Standard" then I just learned I can write code for it. I can even use my existing .NET Standard libraries. You can see the full spread of .NET Standard versions to supported runtimes in this table.
Now, you could target a runtime - a specific .NET - or you can be more flexible and target .NET Standard. Why lock yourself down to a single operating system or specific version of .NET? Why not target a list of APIs that are supported on a ton of platforms?
The person who emailed me wanted to "run a .NET Core Library on WinForms." Tease apart that statement. What they really want is to reuse code - a dll/library specifically.
When you make a new library in Visual Studio 2017 you get these choices. If you're making a brand new library that you might want to use in more than one place, you'll almost always want to choose .NET Standard.
.NET Standard isn't a runtime or a platform. It's not an operating system choice. .NET Standard is a bunch of APIs.
Next, check properties and decide what version of .NET Standard you need.
The .NET Core docs are really quite good, and the API browser is awesome. You can find them at https://docs.microsoft.com/dotnet/
The API browser has all the .NET Standard APIs versioned. You can put the version in the URL if you like, or use this nice interface. https://docs.microsoft.com/en-us/dotnet/api/?view=netstandard-2.0
You can check out .NET Standard 1.6, for example, and see all the namespaces and methods it supports. It works on Windows 10, .NET Framework 4.6.1 and more. If you need to make a library that works on Windows 8 or an older .NET Framework like 4.5, you'll need to choose a lower .NET Standard version. The table of supported platforms is here.
From the docs - When choosing a .NET Standard version, you should consider this trade-off:
- The higher the version, the more APIs are available to you.
- The lower the version, the more platforms implement it.
In general, we recommend you to target the lowest version of .NET Standard possible. The goal here is reuse. You can also check out the Portability Analyzer and run it on your existing libraries to see if the APIs you need are available.
.NET Standard is what you target for your libraries, and the apps that USE your library target a platform.
I emailed them back briefly, "Try making the library netstandard instead."
They emailed back just a short email, "Yes! That did the trick!"
Sponsor: Big thanks to Raygun! Don't rely on your users to report the problems they experience. Automatically detect, diagnose and understand the root cause of errors, crashes and performance issues in your web and mobile apps. Learn more.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
Now its time for me to get back to work and recreate a couple of libraries collegues created in the wrong project types/.Net version that won't run/compile/work in the stack we're actually using.
How Do You Reference a .NET Standard Library from a .NET Framework 4.5 Console Application in Visual Studio 2017?
And then there's the whole matter of targeting multiple frameworks.
Lots of variables in there: target framework for assembly under test, test assembly, and test runner. Maybe a part 2 in the future?
Which library, and how do you "make" it netstandard? They said they were developing WinForms app, not a library.
According to the .NET Standard version table, Standard 1.6 is not supported on Framework 4.6.1, however I can (thankfully) target an ASP.NET Core app to run on Framework 4.6.1. This allows me to pull in Framework 4.6.1 based libraries, for functionality that isn't supported in .NET Standard 1.4.
However, if I want to include NuGet package Microsoft.AspNetCore.Mvc.Core, I cannot import this in a Standard 1.4 library, because it depends on Standard 1.6. And I cannot upgrade to Standard 1.6, because I cannot reference a Standard 1.6 library form a host app that targets Framework 4.6.1.
Unfortunately that library includes a very important interface: IActionContextAccessor.
However, I can change the library to Framework 4.6.1, depend on the NuGet package becase it can also target Framework 4.5.1, and then reference that in the host app?
But in future, when 2.0 tooling is released (still in preview) then it's possible to refer to a Standard 1.6 library from a Framework 4.6.1 host application.
Comments are closed.
Awesome explanation! I really like this clear statement ".NET Standard isn't a runtime or a platform. It's not an operating system choice. .NET Standard is a bunch of APIs." And the way you helped solve the problem, that is to find the real problem
""run a .NET Core Library on WinForms." Tease that apart that statement. What they really want is to reuse code - a dll/library specifically."