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:
In the open component installation window, choose Individual Components tab and type WSL within the search box:
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
:
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:
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:
- Choose Start no client option on the second screen (the default) and press Next button:
- Add Disable access control option to the default options on the third screen and press Next:
- Press Finish button on the fourth screen:
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:
As an alternative to xterm, you can also try xclock - the Linux clock window should popup:
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:
ConsoleAppForLinuxSubsystemDebuggingDemo
- simple non-visual Linux application sample 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:
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}'");
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.
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.
Click on the WSL option and press Debug button again:
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:
<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:
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:
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:
{
"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:
- Open the Linux shell by running:
wsl --install -d Ubuntu
in Windows command prompt. -
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:
A window pops up showing the X term icon in its top left corner:
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