Powrót do strony głównej

gRPC IPC dla .NET desktopów: rozdzielenie logiki UI

Artykuł opisuje architekturę aplikacji desktopowej .NET z podziałem UI i logiki biznesowej za pomocą gRPC i IPC. Headless backend zapewnia niezawodność, thin client — UX. Przykłady proto, Rx.NET i cyklu życia procesów.

gRPC i IPC w .NET: niezawodna architektura desktopowa bez monolitu
Advertisement 728x90

Rozdzielenie UI i logiki biznesowej w aplikacjach desktopowych .NET przy użyciu gRPC i IPC

W aplikacjach desktopowych na WPF lub Avalonia UI logika biznesowa jest ściśle powiązana z wątkiem UI. Zawieszenie renderowania lub awaria XAML prowadzi do zatrzymania całego systemu: timery się resetują, zapytania API przerywają, stan jest tracony. Jest to krytyczne dla zadań w tle, takich jak zarządzanie inteligentnym domem, blokowanie procesów czy odtwarzacz multimedialny.

Rozwiązanie — rozdzielenie na headless backend (Worker Service) i thin client (UI). Komunikują się one przez gRPC z server-side streaming, zapewniając niezależność procesów.

Architektura: dwa procesy, bezpieczna komunikacja

Backend (Axorith.Host) — .NET Worker Service, kompilowany jako WinExe. Odpowiada za:

Google AdInline article slot
  • Przechowywanie stanu sesji.
  • Timery i orkiestrację modułów.
  • Integrację z Home Assistant, Spotify, monitorowanie procesów przez ETW.
  • Zarządzanie przeglądarką przez Named Pipes.

Zużycie w stanie spoczynku: 20–30 MB RAM. Działa autonomicznie, niezależnie od UI.

Frontend (Axorith.Client) na Avalonia UI z ReactiveUI. Tylko wizualizacja i wprowadzanie danych. UI można zakończyć w Menedżerze zadań — backend będzie kontynuował pracę.

Zależności warstw:

Google AdInline article slot
  • Client i Host odwołują się do Axorith.Contracts (gRPC proto).
  • Wspólny Core dla silnika sesyjnego.
  • Shared dla narzędzi i kodu zależnego od platformy.
  • Moduły (wtyczki) zależą od Sdk.

gRPC z server-side streaming dla reaktywności

gRPC wybrano ze względu na kontrakty protobuf i streaming. Proto dla aktualizacji ustawień:

syntax = "proto3";

package axorith.contracts;

service ModulesService {
    rpc StreamSettingUpdates (StreamSettingUpdatesRequest) returns (stream SettingUpdate);
}

message SettingUpdate {
    string module_instance_id = 1;
    string setting_key = 2;
    SettingProperty property = 3;

    oneof value {
        string string_value = 4;
        bool bool_value = 5;
        int32 int_value = 6;
        double number_value = 7;
        ChoiceList choice_list = 8;
    }
}

Na host: SettingUpdateBroadcaster z Rx.NET Subject. Zmiany w modułach (np. przełączenie utworu) są wypychane do strumienia.

Na client: przy starcie otwierany jest strumień, aktualizacje trafiają do ViewModel. ReactiveUI zapewnia natychmiastowe przerysowanie bez opóźnień.

Google AdInline article slot

Zalety nad pollingiem:

  • Brak opóźnień (push zamiast odpytywania).
  • Efektywne wykorzystanie ruchu sieciowego.
  • Ścisła typizacja protobuf zapobiega desynchronizacji.

Bezpieczny IPC zamiast TCP

Lokalne porty są podatne na ataki: konflikty, dostęp wirusów, wyskakujące okienka firewalla. Przejście na IPC:

| Platforma | Transport | ACL |

|-----------|-----------|-----|

| Windows | Named Pipes (ListenNamedPipe) | Tylko bieżący użytkownik |

| Linux/macOS | Unix Domain Sockets (ListenUnixSocket) | Uprawnienia plikowe |

Host zapisuje endpoint w %AppData%/Axorith/host-info.json. Client odczytuje i łączy się. Pełna izolacja procesów.

Cykl życia i UX

Podejście Client-first:

  • Uruchomienie Client.exe.
  • Sprawdzenie host-info.json, automatyczne uruchomienie Host w tle.
  • Zamknięcie okna — minimalizacja do zasobnika (--tray mode).
  • Ikona w zasobniku do restartu/zatrzymania Host lub rozwinięcia UI.

Wykrywanie zerwania połączenia: HTTP/2 Keep-Alive rejestruje przerwanie strumienia. Host wysyła powiadomienie systemowe (Windows Toast / D-Bus).

Test niezniszczalności:

  • Sesja "Work": Spotify gra, YouTube zablokowany.
  • Zakończ Client w Menedżerze zadań.
  • Wynik: backend żyje, sesja kontynuowana.

Trudności wdrożenia

  • Kontrakty: Każda zmiana — regeneracja proto, aktualizacja obu stron.
  • Wersjonowanie: gRPC Interceptor sprawdza x-axorith-version. Niespójność — FailedPrecondition + automatyczna aktualizacja.
  • Asynchroniczność: Wszystkie wywołania Task, obsługa timeoutów, błędów sieciowych na localhost.

Co jest ważne

  • Rozdzielenie procesów eliminuje single point of failure w wątku UI.
  • gRPC streaming + Rx.NET dają reaktywny UI bez polling.
  • IPC (Named Pipes/UDS) zapewnia bezpieczeństwo bez portów.
  • Client-first UX ukrywa złożoność przed użytkownikiem.
  • Nadaje się dla aplikacji 24/7 z zarządzaniem systemowym.

— Editorial Team

Advertisement 728x90

Czytaj dalej