LXC で .Net SDK
〜 Linux で X と Windows の実行ファイルを作成 〜
2025-09-09 作成 福島
TOP > tips > lxc-dotnet
[ TIPS | TOYS | OTAKU | LINK | MOVIE | CGI | AvTitle | ConfuTerm | HIST | AnSt | Asob | Shell ]

0. 前置き

 LXC に .Net SDK をインストールし、C# と VB を使用してコンソールアプリのスケルトンを実行します。
 そのあと、Avalonia のテストプログラムを C# で作成し、Xvfb + VNC で実行します。


1. .Net SDK のインストール

LXC を使用する場合は、該当コンテナにログイン (or アタッチ) してから操作する。

1-1. .Net SDK 9.0 をインストールする。(464 MB)
$ su
# dnf install -y epel-release
# dnf install -y dotnet-sdk-9.0
# dotnet --version
9.0.109 
# exit
$
1-2. C# の動作確認をする。(コンソールアプリ)
$ dotnet new console -lang C# -o ./ConsoleCS/  # -lang には {C# F# VB} を指定する。(省略すると C# になる)
$ cat ./ConsoleCS/Program.cs
 // See https://aka.ms/new-console-templete for more information
Console.WriteLine("Hello, World!");
Main がエントリポイントだが、Main を省略可能。
$ dotnet run --project ./ConsoleCS/ConsoleCS.csproj
Hello, World!
$ ls -lhog ./ConsoleCS/bin/Debug/net9.0/
total 120K
-rwxr-xr-x. 1  91K Sep  4 20:39 ConsoleCS
-rw-r--r--. 1  397 Sep  4 20:39 ConsoleCS.deps.json
-rw-r--r--. 1 4.5K Sep  4 20:39 ConsoleCS.dll
-rw-r--r--. 1  11K Sep  4 20:39 ConsoleCS.pdb
-rw-r--r--. 1  257 Sep  4 20:39 ConsoleCS.runtimeconfig.json
1-3. VB の動作確認をする。(コンソールアプリ)
$ dotnet new console -lang VB -o ./ConsoleVB/
$ cat ./ConsoleVB/Program.vb
Imports System

Module Program
    Sub Main(args As String())
        Console.WriteLine("Hello World!")
    End Sub
End Module
Main がエントリポイント。ファイル名は関係しない。Main が複数存在するとエラーになる。
$ dotnet run --project ./ConsoleVB/ConsoleVB.vbproj
Hello World!
$ ls -lhog ./ConsoleVB/bin/Debug/net9.0/
total 120
-rwxr-xr-x. 1  91K Sep  4 20:49 ConsoleVB
-rw-r--r--. 1  397 Sep  4 20:49 ConsoleVB.deps.json
-rw-r--r--. 1 4.5K Sep  4 20:49 ConsoleVB.dll
-rw-r--r--. 1  11K Sep  4 20:49 ConsoleVB.pdb
-rw-r--r--. 1  257 Sep  4 20:49 ConsoleVB.runtimeconfig.json


2. Avalonia を実行

2-1. X の環境を用意する。
実行環境はこちら (KVM で LXC)こちら (LXC で GUI) を参照。
GUI なしで Avalonia を実行すると、例外「XOpenDisplay failed」により異常終了する。

$ Xvfb :1 -screen 0 640x480x24 &       # Xvfb を用意する。(DISPLAY=:1.0 をここで用意)
$ x11vnc -display :1.0 -rfbport 5901 -nopw & # X を VNC サーバとしてリンクする。
$ DISPLAY=:1.0 openbox &           # ウィンドウマネージャを起動する。(これがないと枠が表示されない)

GUI 環境を終了させるには以下のようにする。
$ ps ax | grep 'Xvfb :1'
   3001 pts/5    S      0:01 Xvfb :1 -screen 0 640x480x24    ← これ  
   3002 pts/5    S+     0:00 grep --color=auto Xvfb :1

$ kill 3001
2-2. Avalonia のテンプレートで C# のプロジェクトを作成する。
$ dotnet new install Avalonia.Templates
削除するには dotnet new uninstall Avalonia.Templates を実行する。

$ dotnet new avalonia.app -lang C# -o ./AvaCS/

$ dotnet list ./AvaCS/AvaCS.csproj package
   [net9.0]:
   Top-level Package             Requested   Resolved  
   > Avalonia                    11.3.5      11.3.5
   > Avalonia.Desktop            11.3.5      11.3.5
   > Avalonia.Diagnostics        11.3.5      11.3.5
   > Avalonia.Fonts.Inter        11.3.5      11.3.5
   > Avalonia.Themes.Fluent      11.3.5      11.3.5

2-3. Avalonia のプロジェクトを実行する。(インタープリタ)
$ DISPLAY=:1.0 dotnet run --project ./AvaCS/AvaCS.csproj # 作成した Avalonia プロジェクトを実行する。

Windows から TightVNC(Viewer) で接続する。
− □ × 
 >_ Windows PowerShell ×   + |
 
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows  

PS C:\> # TightVNC Viewer を起動する
PS C:\> & "C:\Program Files\TightVNC\tvnviewer.exe" 192.168.11.20:1159 

PS C:\> exit 

 ⇓

2-4. Avalonia の実行ファイルを作成する。
.Net SDK (6 以上) では 32bit の実行ファイルを作成することができない。
Windows11 から 32bit 版が存在しないため、今後問題になることはないと予測される。
(古い Linux では問題が起きるかもしれない)

実行ファイルを生成 (Linux 用)
$ dotnet publish ./AvaCS/AvaCS.csproj -c Release -r linux-x64 --self-contained true \
/p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true \
-o ./publishdir/

実行ファイルを生成 (Windows 用)
$ dotnet publish ./AvaCS/AvaCS.csproj -c Release -r win-x64 --self-contained true \
/p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true \
-o ./publishdir/

$ LANG=c tree ./publishdir/
./publishdir/
|-- AvaCS     ← Linux 用 (ELF バイナリ)
|-- AvaCS.exe ← Windows 用 (実行ファイル)
`-- AvaCS.pdb ← デバッグ情報(不要)

0 directories, 3 files
2-5. Linux 用実行ファイルを X で実行する。
$ DISPLAY=:1.0 ./publishdir/AvaCS

 → 実行画面は上記 2-3 と同じ。


3. プログラムを作成してみる

3-1. 変更前のプログラムを確認。(初期のひな形プログラム)
$ cat ./AvaCS/MainWindow.axaml

画面の部品構成を定義するファイル
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaCS.MainWindow"
        Title="AvaCS">
    Welcome to Avalonia!
</Window>

$ cat ./AvaCS/MainWindow.axaml.cs

画面部品のアクションを記述するファイル
using Avalonia.Controls;

namespace AvaCS;

public partial class MainWindow : Window  
{
    public MainWindow()
    {
        InitializeComponent();
    }
}
3-2. テキストを TextBlock にしておく
他のパーツと混在させるときにややこしくなるのを防ぐ。

< ./AvaCS/MainWindow.axaml >
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaCS.MainWindow"
        Title="AvaCS">
    <TextBlock Text="Welcome to Avalonia!" />
</Window>
3-3. ボタンを追加
ブロック <Window> は、一度に複数の要素を内包できない。
複数を一つの要素として扱うために <StackPanel> でまとめる。

< ./AvaCS/MainWindow.axaml >
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaCS.MainWindow"
        Title="AvaCS">
    <StackPanel>
    <TextBlock Text="Welcome to Avalonia!" />
    <Button Content="Click me." Width="80" Height="32" Click="OnButtonClick" />
    </StackPanel>
</Window>
ここではボタンにアクション Click= として OnButtonClick を指定している。
その場合は対応する名前の処理を *.cs に記述しなければならない。(記述しないとエラーになる)

< ./AvaCS/MainWindow.axaml.cs >
using Avalonia.Controls;
using Avalonia.Interactivity;  // RoutedEventArgs を使う

namespace AvaCS;

public partial class MainWindow : Window  
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void OnButtonClick(object? sender, RoutedEventArgs e)  
    {
        // ボタンの処理をここに記述する
        (sender as Button)?.SetValue(ContentProperty, "Clicked");
    }
}
3-4. MessageBox を追加
プロジェクトに MessageBox を追加する。
$ dotnet add ./AvaCS/AvaCS.csproj package MessageBox.Avalonia

< ./AvaCS/MainWindow.axaml.cs >
using Avalonia.Controls;
using Avalonia.Interactivity;   // RoutedEventArgs を使う
using MsBox.Avalonia;           // MessageBoxManager を使う
using MsBox.Avalonia.Enums;     // ButtonEnum を使う
using System;                   // Console を使う

namespace AvaCS;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private async void OnButtonClick(object? sender, RoutedEventArgs e)
    {
        // ボタンの処理をここに記述する
        //(sender as Button)?.SetValue(ContentProperty, "Clicked");
        var msgBox = MessageBoxManager.GetMessageBoxStandard(
                        "タイトル", "メッセージ",
                        ButtonEnum.OkCancel,
                        MsBox.Avalonia.Enums.Icon.Question);

        this.IsEnabled = false;  // MainWindow のアクションを無効にする  
        var result = await msgBox.ShowAsync();
        this.IsEnabled = true;   // MainWindow のアクションを有効にする

        if (result == ButtonResult.Ok)
        {
            Console.WriteLine("OK Clicked.");
        }
    }
}
ここで使用している msgBox.ShowAsync() は処理をブロックせず、MainWindow をクリックすると後ろに隠れてしまうので注意。
Windows の MessageBox のような動作をさせるには作り込みが必要。
3-5. プロジェクトを実行する。(インタープリタ)
$ DISPLAY=:1.0 dotnet run --project ./AvaCS/AvaCS.csproj

Windows から TightVNC(Viewer) で接続する。
− □ × 
 >_ Windows PowerShell ×   + |
 
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows  

PS C:\> # TightVNC Viewer を起動する
PS C:\> & "C:\Program Files\TightVNC\tvnviewer.exe" 192.168.11.20:1159 

PS C:\> exit 

 ⇓