如何无终结点创建WCF ChannelFactory?WCF Client异步实现咨询
问题2:异步WCF Client的安全封装(避开using语句的坑)
太懂你的痛点了!用using包裹WCF客户端真的是大坑——万一Dispose时抛出异常,会直接掩盖原本的业务异常,排查问题超麻烦。你的异步封装思路完全正确,我帮你补全代码并优化细节:
完整的通用异步封装实现
// 带返回值的版本 public static async Task<TReturn> UseServiceAsync<TChannel, TReturn>(Func<TChannel, Task<TReturn>> code) where TChannel : class { var channelFactory = new ChannelFactory<TChannel>("NetTcpBinding_IMyService"); TChannel channel = null; bool operationSuccess = false; try { channel = channelFactory.CreateChannel(); // 执行你的异步业务逻辑 var result = await code(channel); // 只有操作成功时才尝试关闭通道(故障状态下Close会抛异常) ((ICommunicationObject)channel).Close(); operationSuccess = true; return result; } catch { // 出错时强制中止通道,避免资源泄漏 if (channel != null) { ((ICommunicationObject)channel).Abort(); } // 别吃掉异常!把原始异常抛给上层处理 throw; } finally { // 兜底检查:未成功关闭的话必须中止通道 if (!operationSuccess && channel != null) { ((ICommunicationObject)channel).Abort(); } // 别忘了释放ChannelFactory本身 channelFactory?.Close(); } } // 无返回值的重载版本,适配不同场景 public static async Task UseServiceAsync<TChannel>(Func<TChannel, Task> code) where TChannel : class { var channelFactory = new ChannelFactory<TChannel>("NetTcpBinding_IMyService"); TChannel channel = null; bool operationSuccess = false; try { channel = channelFactory.CreateChannel(); await code(channel); ((ICommunicationObject)channel).Close(); operationSuccess = true; } catch { if (channel != null) { ((ICommunicationObject)channel).Abort(); } throw; } finally { if (!operationSuccess && channel != null) { ((ICommunicationObject)channel).Abort(); } channelFactory?.Close(); } }
几个关键注意点
- 必须处理
ICommunicationObject状态:WCF通道进入故障状态后,Close()会抛出异常,这时候必须用Abort()强制释放资源,否则会内存泄漏。 - 不要吞噬异常:catch块一定要重新抛出原始异常,不然上层代码根本无法定位问题根源。
- 复用ChannelFactory提升性能:ChannelFactory创建成本不低,如果服务调用频繁,建议把它做成单例或用依赖注入管理生命周期,下面是优化后的复用版本:
复用ChannelFactory的优化版本
// 初始化单例ChannelFactory,复用它 private static readonly ChannelFactory<IMyService> _cachedChannelFactory = new ChannelFactory<IMyService>("NetTcpBinding_IMyService"); public static async Task<TReturn> UseCachedServiceAsync<TReturn>(Func<IMyService, Task<TReturn>> code) { IMyService channel = null; bool operationSuccess = false; try { channel = _cachedChannelFactory.CreateChannel(); var result = await code(channel); ((ICommunicationObject)channel).Close(); operationSuccess = true; return result; } catch { if (channel != null) { ((ICommunicationObject)channel).Abort(); } throw; } finally { if (!operationSuccess && channel != null) { ((ICommunicationObject)channel).Abort(); } } }
使用示例
带返回值场景:
var userInfo = await UseServiceAsync<IMyService, UserInfo>(async client => { return await client.GetUserInfoAsync(1001); });
无返回值场景:
await UseServiceAsync<IMyService>(async client => { await client.UpdateUserInfoAsync(new UserInfo { Id = 1001, Name = "Marshall" }); });
这样封装后,既避开了using的坑,又能安全使用异步WCF客户端啦!
内容的提问来源于stack exchange,提问作者Marshall
相关产品推荐
相关产品推荐

