.NET Core 2.0: Referencing .NET Framework Libraries: A Topshelf Experiment

Referencing .NET Framework Libraries in .NET Core 1.1

There are many old libraries targeting the .NET Framework which, for various reasons, do not yet target .NET Core or .NET Standard. Topshelf, a fantastic library that helps you to easily create Windows services, is one of these. At the time of writing this article, the last release of Topshelf was 4.0.3 back in October 2016. There was no way that Topshelf could target .NET Standard because the .NET Standard spec did not support the APIs that are required for it to function.

This was a problem because there was no way you could create a Windows service using Topshelf for a .NET Core 1.1 application. Simply trying:

Install-Package Topshelf

…is bound to fail miserably:

If you want to make a Windows service out of an application targeting .NET Core 1.1, then you have to use an alternative such as NSSM.

What Changed in .NET Core 2.0

With the release of .NET Core 2.0 and .NET Standard 2.0, applications or libraries targeting either of these are able to reference old libraries targeting the full .NET Framework. Presumably this is because the .NET Core/Standard 2.0 implementations have enough API coverage to overlap with what the full framework was able to offer.

Quoting the .NET Core/Standard 2.0 announcement linked above:

“You can now reference .NET Framework libraries from .NET Standard libraries using Visual Studio 2017 15.3. This feature helps you migrate .NET Framework code to .NET Standard or .NET Core over time (start with binaries and then move to source). It is also useful in the case that the source code is no longer accessible or is lost for a .NET Framework library, enabling it to be still be used in new scenarios.

“We expect that this feature will be used most commonly from .NET Standard libraries. It also works for .NET Core apps and libraries. They can depend on .NET Framework libraries, too.

“The supported scenario is referencing a .NET Framework library that happens to only use types within the .NET Standard API set. Also, it is only supported for libraries that target .NET Framework 4.6.1 or earlier (even .NET Framework 1.0 is fine). If the .NET Framework library you reference relies on WPF, the library will not work (or at least not in all cases). You can use libraries that depend on additional APIs,but not for the codepaths you use. In that case, you will need to invest singificantly in testing.”

Example with Topshelf

In order to actually test this out, you’ll need to have Visual Studio 15.3 or later. You will also need to separately install the .NET Core 2.0 SDK.

In an earlier section, we tried installing Topshelf in a .NET Core 1.1 application, and failed. Let’s try doing the same thing with a .NET Core 2.0 application:

Install-Package Topshelf

The package installation works pretty well:

However, the warning that shows under the dependency is not very promising:

There’s only one way to find out whether this will actually work in practice.

Let’s steal the code from the Topshelf quickstart documentation:

public class TownCrier
{
    readonly Timer _timer;
    public TownCrier()
    {
        _timer = new Timer(1000) {AutoReset = true};
        _timer.Elapsed += (sender, eventArgs) => Console.WriteLine("It is {0} and all is well", DateTime.Now);
    }
    public void Start() { _timer.Start(); }
    public void Stop() { _timer.Stop(); }
}

public class Program
{
    public static void Main()
    {
        HostFactory.Run(x =>                                 //1
        {
            x.Service<TownCrier>(s =>                        //2
            {
               s.ConstructUsing(name=> new TownCrier());     //3
               s.WhenStarted(tc => tc.Start());              //4
               s.WhenStopped(tc => tc.Stop());               //5
            });
            x.RunAsLocalSystem();                            //6

            x.SetDescription("Sample Topshelf Host");        //7
            x.SetDisplayName("Stuff");                       //8
            x.SetServiceName("Stuff");                       //9
        });                                                  //10
    }
}

Nope, looks like Topshelf won’t work even now.

I guess the APIs supported by .NET Core 2.0 still do not have enough functionality for Topshelf work as-is. Other .NET Framework libraries may work though, depending on the dependencies they require. In the “.NET Core 2.0 Released!” video, one of the demos shows SharpZipLib 0.86 (last released in 2011) being installed in an ASP .NET Core 2.0 application. It is shown to build, but we don’t get to see whether it works at runtime.

It is still early, and I suppose we have yet to learn more about the full extent of support for .NET Framework libraries from .NET Core 2.0 applications and .NET Standard 2.0 libraries. The problem is that when evaluating a third-party library such as Topshelf, it’s difficult to determine whether its own dependencies fall within the .NET Standard API set. This looks to me like a matter of pure trial and error.