Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Running and Debugging Multiplatform .NET (.NET Core, .NET5 and .NET6) GUI and Console Applications on Windows Subsystem for Linux (WSL)

5.00/5 (22 votes)
26 Dec 2023CPOL9 min read 31K  
This article describes how to test and debug .NET/Avalonia Linux applications using WSL.
This article details how to use the very powerful combination of .NET and Avalonia together with WSL for the purpose of debugging Linux .NET applications while they are being developed within Visual Studio 2022 on Windows.

A Plea for Votes and Comments

Friends, I noticed a lot of people are reading this article and some told me or somehow indicated that they liked it, but not many are voting for it. Please vote and write comments telling me what you liked and disliked about the article so that I could improve my article writing skills. Thank you!

What this Article is About

.NET Standard, CORE .NET5 and .NET6 made .NET multiplatform (aside from the GUI programs). Avalonia filled the gap allowing multiplatform GUI programs to also be developed in .NET.

WSL2 - latest release of Windows Subsystem for Linux, allows the Linux programs (including those developed with .NET and Avalonia) to be tested straight on Windows (without moving them to a Linux computer or a virtual box).

Finally, Visual Studio 2022 enables debugging Linux programs developed with .NET and Avalonia on Windows without moving them anywhere.

This article details how to properly install and use this very powerful combination of Microsoft's packages and Avalonia for the purpose of debugging Linux .NET core applications while they are being developed within Visual Studio 2022.

Operating Systems and Packages Used in this Article

Recent versions of Windows (10 and 11) allow running a Linux system within the Windows platform. This can be very handy especially for testing and debugging multiplatform or Linux specific programs built on Windows using Visual Studio.

I am especially interested in multiplatform applications both console and GUI built with new open source .NET releases (.NET STANDARD, .NET CORE, .NET5 and .NET6).

All those versions of .NET listed above are multiplatform aside for the libraries for building the Desktop UI applications (WPF and WinForms). Here is where an open source package for building Multipatform GUI applications - Avalonia comes in very handy. It provides the missing link making UI .NET functionality also multiplatform.

Avalonia is a spiritual descendant of WPF, but more powerful than WPF and can be used for

  • Desktop solutions that will run across Windows, Mac and Linux
  • Web applications to run in Browser (via WebAssembly)
  • Mobile applications for Android, iOS and Tizen.

I call Avalonia Multiplatform WPF++.

I wrote a lot about Avalonia in the past, in particular, I explained in Multiplatform UI Coding with AvaloniaUI in Easy Samples why Avalonia is far better than Xamarin, MAUI, Node.js or UNO Platform for creating multiplatform UI applications.

When you create an application that has to run on Linux, it has to be tested and sometimes debugged on Linux also, since there can be some Linux specific code and even Linux specific bugs in a code that is supposed to run on multiple platforms.

For Windows developers (and most of those who develop with .NET - develop on Windows), Windows Subsystem for Linux (WSL) comes in very handy allowing to run a Linux .NET application on the same Windows machine on which the code is developed and even to debug it using Visual Studio 2022.

This article describes how to run and debug Linux .NET code applications on Windows 10 using Visual Studio 2022.

Windows and Visual Studio Versions

For my tests, I used Windows 11 and Visual Studio 2022.

I am not sure if the previous version of Visual Studio (VS2019) also allows debugging .NET Linux applications, but even if it does, it probably has more quirks to overcome, so I recommend using VS2022. My experience with it was virtually painless.

Installing WSL2 on Windows 10 and 11

I am not listing all the steps required to install WSL2 (an advanced version of WSL) onto Windows 10 and 11 OS. There are many web sites that detail it, e.g., How to Install WSL 2 on Windows 10 and How to install Linux WSL2 on Windows 10 and Windows 11.

I understand that installing WSL2 on Windows 11 is considerably easier than installing it on Windows 10.

Installing Visual Studio 2022 Component for Debugging with WSL

There is a Visual Studio component that needs to be installed (or verified that it is installed).

Within Visual Studio, open Tools menu and choose Get Tools and Features... menu item:

Image 1

In the open component installation window, choose Individual Components tab and type WSL within the search box:

Image 2

Component .NET Debugging with WSL should show. Install the component (unless already installed).

Running the WSL Linux Shell (Outside of the Visual Studio)

To start a Linux shell from a Windows Command shell, use the following command:

wsl --install -d Ubuntu  

If you do it the first time, it might ask you to set up the user name and the password; then the Linux shell will open.

Within the Linux shell, you can try your favorite UNIX commands, e.g., ls, cat or grep:

Image 3

You can reach your Linux home by going to "\\wsl$\Ubuntu\home\<linux-acct-name>" in Windows command line or in the Explorer. This might be needed, e.g., to copy some files or folders between your Windows OS and Linux.

Your can install your favorite Linux programs in the same way they are installed on a real Linux machine, e.g. by typing:

sudo apt install emacs

within Linux shell.

Running a UI Program from a Linux Shell

Here, I show how to run any Linux UI program (not necessarily a .NET one) from a WSL Linux shell.

On Windows 10 or 11, you need to download, install and run VcXsvr application from sourceforge.net/projects/vcxsrv/.

Installation will result in XLaunch icon on your desktop:

Image 4

In order to run VcXsrv, you have to click this icon, and then go through the following steps:

  • Choose Multiple Windows option on the first screen (the default) and press Next button:

    Image 5

  • Choose Start no client option on the second screen (the default) and press Next button:

    Image 6

  • Add Disable access control option to the default options on the third screen and press Next:

    Image 7

  • Press Finish button on the fourth screen:

    Image 8

Now try to run some command in the Linux shell that starts a Linux UI application, e.g.:

xterm  

It will result in the following errors:

xterm: Xt error: Can't open display:
xterm: DISPLAY is not set  

We need to set the DISPLAY variable on your Linux system to contain <your-windows-ip-address>:0.0. The magic line that does it for you in WSL Linux shell (at least for Ubuntu 20.04) is:

export DISPLAY=$(route.exe print | grep 0.0.0.0 | head -1 | awk '{print $4}'):0.0  

Once you run this line, try:

echo $DISPLAY  

to see what your DISPLAY variable was set to. In my case, it was:

10.0.0.7:0.0  

It is also recommended that you run:

export LIBGL_ALWAYS_INDIRECT=1  

in order to avoid some error messages.

Now run xterm command again and voila, you have your fully functional xterm popping out of the Linux shell as one of the windows:

Image 9

As an alternative to xterm, you can also try xclock - the Linux clock window should popup:

Image 10

Debugging .NET Project on WSL Using Visual Studio 2022

Code Location

Both projects visual and non-visual are part of NP.Ava.Demos repository. You can download the whole repository using Github's "download as zip" option or clone the repository using git's clone command:

git clone https://github.com/npolyak/NP.Ava.Demos.git  

The two projects for these articles are:

  1. ConsoleAppForLinuxSubsystemDebuggingDemo - simple non-visual Linux application sample
  2. AvaloniaAppForLinuxSubsystemDebuggingDemo - example of a simple visual application for Linux

Debugging Console (Non-Visual) Linux Application

Open ConsoleAppForLinuxSubsystemDebuggingDemo.sln solution under ConsoleAppForLinuxSubsystemDebuggingDemo folder of the repository.

The purpose of the code within Program.cs file is to print some information about the operating system that is running the program:

C#
bool isLinux = OperatingSystem.IsLinux();

if (isLinux)
{
    Console.WriteLine("Yes, it is Linux!!!");
}
else
{
    Console.WriteLine("No, it is not Linux");
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
    Console.WriteLine("Yes, indeed Linux!!!");
}

Console.WriteLine($"RuntimeInformation.OSDescription = 
                   '{RuntimeInformation.OSDescription}'");

// gives Linux type, version number and architecture:
Console.WriteLine($"RuntimeInformation.RuntimeIdentifier = 
                   '{RuntimeInformation.RuntimeIdentifier}'");

Console.WriteLine($"Environment.OSVersion = '{Environment.OSVersion}'");  

You debug the program under Windows, by pressing the Debug button after putting some breakpoint in it.

Image 11

Running the program under Windows 10, this program will produce the following output:

No, it is not Linux
RuntimeInformation.OSDescription = 'Microsoft Windows 10.0.19044'
RuntimeInformation.RuntimeIdentifier = 'win10-x64'
Environment.OSVersion = 'Microsoft Windows NT 10.0.19044.0'  

Note that the Debug button (button within the red oval on the picture above), has an arrow pointing down on its right. If you press on the arrow, you shall see a menu opening with WSL option within it.

Image 12

Click on the WSL option and press Debug button again:

Image 13

It will stop at the same breakpoint, but now, the application runs as a Linux program on WSL. The output of this program will be:

Yes, it is Linux!!!
Yes, indeed Linux!!!
RuntimeInformation.OSDescription = 
   'Linux 5.10.60.1-microsoft-standard-WSL2 #1 SMP Wed Aug 25 23:20:18 UTC 2021'
RuntimeInformation.RuntimeIdentifier = 'ubuntu.20.04-x64'
Environment.OSVersion = 'Unix 5.10.60.1'  

Important Note: The output of the Linux program run under WSL is written to the Visual Studio output window, not to an opened console window as the output for the Windows program was.

Debugging an Avalonia GUI .NET Linux Application

Now open AvaloniaAppForLinuxSubsystemDebuggingDemo.sln solution located under the folder of the same name within the NP.Avalonia.Demos repository.

Since now we are going to debug a UI application, do not forget to launch your VcXsrv on Windows 10 as described above (unless such server is already running).

The non-standard code for this very simple UI application is located within files MainWindow.axaml and MainWindow.axaml.cs.

Here is the content of MainWindow.axaml file:

XAML
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaAppForLinuxSubsystemDebuggingDemo.MainWindow"
        Title="AvaloniaAppForLinuxSubsystemDebuggingDemo"
        Width="500"
        Height="300">
	<Button x:Name="TestDebuggingButton"
			Content="Test Debugging"
			HorizontalAlignment="Center"
			VerticalAlignment="Center" />
</Window>  

It defines a single button in the center of the Window named "TestDebuggingButton".

The content of MainWindow.axaml.cs file is just as simple. It defines and adds a handler for the button's Click event:

C#
using Avalonia.Controls;
using Avalonia.Interactivity;

namespace AvaloniaAppForLinuxSubsystemDebuggingDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            TestDebuggingButton.Click += TestDebuggingButton_Click;
        }

        private void TestDebuggingButton_Click(object? sender, RoutedEventArgs e)
        {
           
        }
    }
}

Put a breakpoint within the TextDebugginButton_Click(...) handler method.

Now switch the Debug button to WSL (same way it was done in the previous subsection). Note that the project, now has Properties subfolder containing launchSettings.json file:

Image 14

In our case - this file was committed to the git repository, but when you create a new project, this file will be created and added to the project when you switch the Debug button to WSL.

Click on launchSettings.json file to open it. Here is its content:

JavaScript
{
  "profiles": {
    "AvaloniaAppForLinuxSubsystemDebuggingDemo": {
      "commandName": "Project"
    },
    "WSL": {
      "commandName": "WSL2",
      "environmentVariables": {
        "DISPLAY": "10.0.0.7:0.0",
        "LIBGL_ALWAYS_INDIRECT": "1"
      },
      "distributionName": ""
    }
  }
}  

You need to change the DISPLAY setting to whatever you have. In order to figure out what you need to set DISPLAY variable to, you can use the same method described above in the section Running a UI Program from a Linux Shell, namely:

  1. Open the Linux shell by running:
    wsl --install -d Ubuntu     
    in Windows command prompt.
  2. Within the Linux shell, run the following command:

    echo $(route.exe print | grep 0.0.0.0 | head -1 | awk '{print $4}'):0.0 
    The output of this command will produce the value you need to assign to your DISPLAY variable within launchSettings.json file (in my case it was "10.0.0.7:0.0").

Now you are ready to debug the program.

Start the program by pressing your Debug button:

Image 15

A window pops up showing the X term icon in its top left corner:

Image 16

This is our Avalonia application running on WSL.

Press the button in the middle of the window, you will stop at the breakpoint within the body of TestDebuggingButton_Click(...) method.

Conclusion

This article describes in detail how to test and debug .NET/Avalonia Linux applications using WSL and Visual Studio 2022.

History

  • 24th April, 2022: Initial version
  • 26th December, 2023 - Upgraded to Avalonia 11

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)