I maintain a library with a modest number of users (at least two!) that can read FLAC metadata, in .NET.

Recently I ported it to .NET Standard and published it on NuGet.

Porting a .NET Framework 2.0 library to .NET Standard is one thing. It doesn't mean it will automatically run on all platforms that support .NET Standard.

I can't test it on all those platforms, since I do not have the hardware for it.

But I CAN test it on Linux.

For this, I will need to:

  • Install .NET Core on Linux
  • Port the test project to .NET Core (if possible)
  • Run the tests on Linux

Summary (TL;DR)

My tests show that FlacLibSharp does run on .NET Core for Linux. I didn't have to make changes to the library itself to make it run on Linux.

I did run into some problems:

  • I had to make a test project specifically for Windows to test some File Access problems
  • My tests used windows specific path delimiters (i.e. the backslash in "Data\test.flac")
    • This had to be replaced with a call to Path.Combine
  • A project that targets both .NET Standard and .NET Framework 2.0 cannot be built on Linux
    • I had to make a specific project for .NET Standard only to be able to build and run the tests on Linux as well

See the results on Github: https://github.com/AaronLenoir/flaclibsharp

Installing .NET Core on Linux

I set up a clean VM with Ubuntu, with updates installed, for these tests.

Because Ubuntu is given great support everywhere, there is a dedicate guide from Microsoft on how to deploy it to Ubuntu. I won't duplicate the steps here ...

The only detail not mentioned is that you need curl. So:

sudo apt-get install curl

Following the guide went smoothly and resulted in me running Hello World in .NET Core:

Image showing 'dotnet new console - hwapp'; 'cd hwapp/'; 'dotnet run' results in 'Hello World!' being printed on screen, proving .NET Core builds and runs .NET projects.

Test projects in .NET Core

My first thought was to just change the target platform of my unit test project to .NET Core 2, but that is not possible for such a project. Because it is using an older csproj format.

But once I have the tests in .NET Core, I won't need this old test project anymore ... (I think)

So I must do a "File > New Project" and select "Visual C# > .NET Core > Unit Test Project (.NET Core)".

I will call it "FlacLibSharp.Test.Core".

Rebuilding it will shows the "hello world" test in the "Test Explorer" of Visual Studio. So we are good to go.

Add Dependencies

First of all, the project depends on the FlacLibSharp project itself. Luckily, .NET Core still allows us to reference another project in the solution. So I can add FlacLibSharp directly.

Next, I will copy all files (both test files and source code) from the old .NET Framework test project. I copy because the .NET Core test project will be replacing the old project.

Compilation Issue: Windows Specific Tests

A thing I ran into was a test that would get and set access rights on a test file. This is a test to check whether a Save on a Flac file would clear the original file's access rights. This was a bug reported to me via github.

I won't be able to solve this easily, so for now I will take the following approach:

  • Create two test projects:
    • FlacLibSharp.Test.Core
    • FlacLibSharp.Tests.Windows

In will delete the "FileAccessRightTests" from .Core but leave it for .Windows.

The Windows tests can then do stuff that is specific to Windows. I can then later figure out how to port that test in a cross platform manner. But given the big differences in ACL between platforms, that might be hard.

Everything else compiled fine.

Running the tests on Windows

Running the tests on Windows, I expect little problems and sure enough all tests run fine.

Now I can safely delete all tests from the old FlacLibSharp.Tests project, except the FileAccessRight tests.

And I'll rename FlacLibSharp.Tests to FlacLibSharp.Tests.Windows (and hope git handles this all correctly).

Now, on my dotnetstandard branch I can push this to github and via that way hopefully get the project on Linux.

Running on Linux

I clone the project from github into a local folder:

$ git clone https://github.com/AaronLenoir/flaclibsharp.git
$ cd flaclibsharp
$ git checkout dotnetstandard

To jump straight in I thought to just try the command dotnet test and see what happens. But that gave me a lot of red text which I won't show here. If you are interested it is here: https://gist.github.com/AaronLenoir/d8249fab23cc100587464a35dfada16f

No great success, I guess I should first try to build FlacLibSharp itself. But this produces an error too:

user@ubuntu:~/dotnetcore/flaclibsharp/FlacLibSharp$ dotnet build
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

/usr/share/dotnet/sdk/2.0.0/Microsoft.Common.CurrentVersion.targets(1122,5): error MSB3644: The reference assemblies for framework ".NETFramework,Version=v2.0" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend. [/home/user/dotnetcore/flaclibsharp/FlacLibSharp/FlacLibSharp.csproj]

During my porting I had added two target platforms to FlacLibSharp, so that my NuGet package would contain a dll for .NET Standard 1.3 but also for .NET Framework 2.0:

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

  <PropertyGroup>
    <TargetFrameworks>netstandard1.3;net20</TargetFrameworks>
    ....

It looks like that decision has come back to bite me.

If I remove net20 from the TargetFrameworks the build succeeds:

user@ubuntu:~/dotnetcore/flaclibsharp/FlacLibSharp$ dotnet build
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  FlacLibSharp -> /home/user/dotnetcore/flaclibsharp/FlacLibSharp/bin/Debug/netstandard1.3/FlacLibSharp.dll
  Successfully created package '/home/user/dotnetcore/flaclibsharp/FlacLibSharp/bin/Debug/FlacLibSharp.3.0.3.nupkg'.

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:03.38

Issue: Targetting Multiple Platforms

In my previous posts, I concluded I did not require two separate projects to target both .NET Framework 2.0 and .NET Core.

I still do not want to do this, because I want them both in the same NuGet package. But I also want to be able to build and test the library on .NET Core specifically. But it's not possible to build projects that also target .NET Framework 2.0.

After the tests run successful I will come back to this issue, with a solution.

Running the .NET Core tests

Ignoring the above issues for now, I want to see if my FlacLibSharp built on Linux can pass the tests.

cd FlacLibSharp.Test.Core
dotnet build

This results in a successful build.

dotnet test

This results in a much less hopeful report:

Total tests: 33. Passed: 0. Failed: 33. Skipped: 0.

The problem in all tests seems to be that the tests files aren't found in the output directory:

Could not find file '/home/user/dotnetcore/flaclibsharp/FlacLibSharp.Test.Core/bin/Debug/netcoreapp2.0/Data\testfile4.flac

Issue: Cross Platform File Path Handling

But actually, the files are there. The problem lies in the way I build up the path in my tests:

string origFile = @"Data\testfile1.flac";

The backslash is fine on Windows but Linux doesn't know what to do with them.

The correct way to build these paths is using Path.Combine:

string origFile = Path.Combine("Data", "testfile1.flac");

So that's a pretty painful replace through all my tests. But after this change I receive the encouraging message:

Total tests: 33. Passed: 33. Failed: 0. Skipped: 0.

Targetting Multiple Platforms

So we saw that on Linux, it's not possible to build a project that targets both .NET Standard and .NET Framework 2.0. This makes sense since .NET Framework 2.0 doesn't exist on Linux.

But we target the two platforms so that the NuGet package can be used by older .NET Framework applications and by applications on a framework compatible with .NET Standard 1.3.

Since I still want to support running tests on Linux, I have used the following approach:

  • Left FlacLibSharp as is (targetting .NET Standard 1.3 and .NET Framework 2.0)
  • Created a new project targetting .NET Standard 1.3 called "FlacLibSharp.Core"
  • Added all files from FlacLibSharp as link to the FlacLibSharp.Core project
  • In the FlacLibSharp.Tests.Core I now reference FlacLibSharp.Core

This allows us to run the tests on linux (but not to make a build for publishing):

$ git clone https://github.com/AaronLenoir/flaclibsharp.git
$ cd flaclibsharp/FlacLibSharp.Tests.Core
$ dotnet test

Showing that running 'dotnet test' in FlacLibSharp.Test.Core results in: 'Total tests: 33. Passed: 33. Failed: 0. Skipped: 0.'

Conclusion

My tests show that FlacLibSharp does run on .NET Core for Linux. I didn't have to make changes to the library itself to make it run on Linux.

I did run into some problems:

  • I had to make a test project specifically for Windows to test some File Access problems
  • My tests used windows specific path delimiters (i.e. the backslash in "Data\test.flac")
    • This had to be replaced with a call to Path.Combine
  • A project that targets both .NET Standard and .NET Framework 2.0 cannot be built on Linux
    • I had to make a specific project for .NET Standard only to be able to build and run the tests on Linux as well

See the results on Github: https://github.com/AaronLenoir/flaclibsharp

Now that I can build and test my things on .NET Core, I'm hoping to revisit integrating Travis CI on my Github repo for automated testing.

Update 29 okt 2017: Read about how I did enable Travis CI.

Feel free to share how you would deal with this.