websocket-sharp OnMessage回调非主线程致WPF事件传递失败求助
问题分析与解决方案
核心问题出在WebSocketBehavior实例与单例实例不匹配:你的WebsocketServer类继承了WebSocketBehavior,但websocket-sharp会为每个客户端连接创建一个全新的WebSocketBehavior子类实例来处理该连接;而MainWindow订阅的是单例WebsocketServer.Instance的事件,实际触发事件的是每个连接对应的独立实例,两者完全不是同一个对象,所以事件永远不会被MainWindow接收到。
修正方案:拆分管理类与连接处理类
将服务器的全局管理(单例、启停)和单个连接的消息处理拆分,让所有连接的事件都通过单例管理类统一触发,确保MainWindow订阅的事件源和实际触发源一致。
1. 创建全局服务器管理类(单例)
public class WebsocketServerManager { private static readonly Lazy<WebsocketServerManager> lazyInstance = new Lazy<WebsocketServerManager>(() => new WebsocketServerManager()); public static WebsocketServerManager Instance => lazyInstance.Value; private const string HOST_IP_ADDRESS = "127.0.0.2"; private const int PORT = 38001; private WebSocketServer _socket; // 供UI层订阅的统一事件 public event EventHandler<EventArgs> RaiseOnScanDevice = (s, e) => { }; private WebsocketServerManager() { Initialize(); } public void Initialize() { _socket = new WebSocketServer(IPAddress.Parse(HOST_IP_ADDRESS), PORT); // 注册连接处理类,并传入当前单例实例 _socket.AddWebSocketService<DeviceWebSocketBehavior>(() => new DeviceWebSocketBehavior(this)); StartServer(); } public void StartServer() => _socket.Start(); public void StopServer() => _socket.Stop(); // 供连接处理类调用,统一触发事件 internal void TriggerScanDeviceEvent() { // 确保在WPF UI线程触发事件 System.Windows.Application.Current.Dispatcher.Invoke(() => { RaiseOnScanDevice?.Invoke(this, EventArgs.Empty); }); } }
2. 创建单个连接的消息处理类
public class DeviceWebSocketBehavior : WebSocketBehavior { private readonly WebsocketServerManager _serverManager; private PacketHandler _packetHandler = new PacketHandler(); public DeviceWebSocketBehavior(WebsocketServerManager serverManager) { _serverManager = serverManager; } protected override Task OnMessage(MessageEventArgs e) { using (var reader = new System.IO.StreamReader(e.Data)) { string message = reader.ReadToEnd(); PacketModel packet = _packetHandler.OpenPacket(message); HandleMessageFromClient(packet); } return base.OnMessage(e); } private void HandleMessageFromClient(PacketModel packet) { if (string.IsNullOrEmpty(packet.EventName)) return; switch (packet.EventName) { case SocketEvent.Hello: Send("OK"); break; case SocketEvent.ScanDevice: // 通过单例管理器触发全局事件 _serverManager.TriggerScanDeviceEvent(); break; } } }
3. 修改MainWindow订阅逻辑
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // 订阅单例管理器的事件 WebsocketServerManager.Instance.RaiseOnScanDevice += SocketConnection_RaiseOnScanDevice; } private void SocketConnection_RaiseOnScanDevice(object sender, EventArgs e) { Console.WriteLine("SocketConnection_RaiseOnScanDevice"); } }
关键修正点说明
- 拆分后,所有客户端连接的消息处理实例都会通过单例
WebsocketServerManager触发事件,MainWindow订阅的是同一个事件源,确保事件能被正确接收。 - 通过
Dispatcher.Invoke强制事件在UI线程触发,彻底解决线程上下文不匹配的问题。
内容的提问来源于stack exchange,提问作者Duc Nguyen
相关产品推荐
相关产品推荐

