使用gRPC与IPC在.NET桌面应用中分离UI与业务逻辑
在WPF或Avalonia UI桌面应用中,业务逻辑通常与UI线程紧密耦合。渲染卡顿或XAML崩溃会导致整个系统停滞:计时器重置、API请求中断、状态丢失。这对于智能家居管理、进程拦截或媒体播放器等后台任务尤为关键。
解决方案是将应用拆分为无头后端(Worker Service)和轻量客户端(UI)。两者通过gRPC进行服务器端流式通信,确保进程独立性。
架构:双进程,安全通信
后端(Axorith.Host)——一个.NET Worker Service,构建为WinExe。负责:
- 存储会话状态。
- 计时器和模块编排。
- 与Home Assistant、Spotify、ETW进程监控集成。
- 通过命名管道管理浏览器。
空闲消耗:20–30 MB内存。自主运行,独立于UI。
前端(Axorith.Client)基于Avalonia UI和ReactiveUI。仅负责可视化和输入。UI可在任务管理器中终止——后端继续运行。
层级依赖:
- 客户端和主机引用Axorith.Contracts(gRPC proto)。
- 共享核心用于会话引擎。
- 共享用于工具和平台相关代码。
- 模块(插件)依赖于Sdk。
使用gRPC服务器端流实现响应式
选择gRPC因其protobuf契约和流式传输能力。用于设置更新的Proto:
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;
}
}
在主机端:SettingUpdateBroadcaster使用Rx.NET Subject。模块中的更改(如曲目切换)被推送到流中。
在客户端:启动时打开流,更新传递到ViewModel。ReactiveUI确保即时重绘无延迟。
相比轮询的优势:
- 无延迟(推送而非轮询)。
- 高效利用流量。
- 强类型protobuf防止不同步。
使用安全IPC替代TCP
本地端口存在风险:冲突、病毒访问、防火墙弹窗。改用IPC:
| 平台 | 传输 | 访问控制列表 |
|-----------|-----------|-----|
| Windows | 命名管道(ListenNamedPipe) | 仅限当前用户 |
| Linux/macOS | Unix域套接字(ListenUnixSocket) | 文件权限 |
主机将端点写入%AppData%/Axorith/host-info.json。客户端读取并连接。实现完全进程隔离。
生命周期与用户体验
客户端优先方法:
- 启动Client.exe。
- 检查host-info.json,自动在后台启动Host。
- 关闭窗口——最小化到托盘(--tray模式)。
- 托盘图标用于重启/停止Host或恢复UI。
连接中断检测:HTTP/2 Keep-Alive检测流中断。主机发送系统通知(Windows Toast / D-Bus)。
韧性测试:
- “工作”会话:Spotify播放,YouTube被拦截。
- 在任务管理器中终止Client。
- 结果:后端存活,会话继续。
实现挑战
- 契约: 每次更改都需要重新生成proto,更新两端。
- 版本控制: gRPC拦截器检查
x-axorith-version。不匹配导致FailedPrecondition + 自动更新。 - 异步: 所有调用基于Task,处理超时和本地网络错误。
关键要点
- 进程分离消除了UI线程的单点故障。
- gRPC流式传输 + Rx.NET实现无需轮询的响应式UI。
- IPC(命名管道/UDS)确保安全,无需端口。
- 客户端优先的UX向用户隐藏复杂性。
- 适用于需要系统管理的24/7应用。
— Editorial Team
暂无评论。