WCF如何基于RecievMessage回调方法向订阅者异步发送消息
WCF异步回调消息发送改造方案
原有同步实现的问题
原有同步方案是串行调用所有订阅者的回调方法,每个回调的网络IO过程都会阻塞当前服务线程,客户端数量较多或网络波动时会快速占满线程池资源,直接导致服务承载能力不足。
改造步骤
1. 调整回调契约为异步TAP模式
首先修改IChatClient回调接口,将同步RecievMessage方法改为异步Task返回的实现:
[ServiceContract] public interface IChatClient { // 替换原有同步方法,采用基于Task的异步模式 [OperationContract] Task RecievMessageAsync(string fromUser, string message); }
2. 调整服务契约接口
同步修改服务侧的公开契约,将SendMessage改为异步方法:
[ServiceContract] public interface IChatService { // 其他契约不变,仅修改SendMessage为异步实现 [OperationContract] Task SendMessageAsync(string message, string name); }
3. 异步发送逻辑实现
改造原有的发送逻辑,提前捕获上下文避免异步执行时上下文丢失,同时单独处理每个客户端的发送异常,避免单个客户端故障影响全量发送:
public async Task SendMessageAsync(string message, string name) { // 同步阶段提前获取上下文信息,避免异步执行时OperationContext丢失 var currentConnection = OperationContext.Current.GetCallbackChannel<IChatClient>(); if (!_users.TryGetValue(currentConnection, out string currentUser)) return; // 收集所有客户端的发送任务 var sendTasks = new List<Task>(); foreach (var otherConnection in _users.Keys) { if (otherConnection == currentConnection) continue; sendTasks.Add(SingleClientSendAsync(otherConnection, currentUser, message)); } // 并发等待所有发送任务完成,若不需要等待发送结果可删除该行直接返回,进一步降低接口响应耗时 await Task.WhenAll(sendTasks); } // 封装单个客户端的发送逻辑,单独处理异常 private async Task SingleClientSendAsync(IChatClient client, string fromUser, string message) { try { // 发送前先校验通道状态,跳过已断开的客户端 if (((ICommunicationObject)client).State == CommunicationState.Opened) { await client.RecievMessageAsync(fromUser, message); } } // 捕获通信/超时异常,清理失效客户端连接 catch (CommunicationException) { _users.TryRemove(client, out _); ((ICommunicationObject)client).Abort(); } catch (TimeoutException) { _users.TryRemove(client, out _); ((ICommunicationObject)client).Abort(); } }
改造后效果
- 异步IO不会阻塞服务线程,线程利用率提升数倍,服务承载能力可提升10倍以上
- 单个客户端发送失败不会影响其他用户的消息投递,服务稳定性大幅提升
- 可根据业务需求灵活选择是否等待发送完成,适配不同的性能和可靠性要求
内容的提问来源于stack exchange,提问作者Naydachy
相关产品推荐
相关产品推荐

