如何处理C# SOAP请求中出现的CommunicationObjectFaultedException异常
问题根因说明
这个CommunicationObjectFaultedException属于WCF调用的常见瞬态异常,不是完全不可避免的,多由网络抖动、服务端临时断连、单次请求超时等场景触发,你的代码确实存在可优化的空间,现有逻辑的缺陷才导致重试没有生效。
原有代码的核心问题
- 捕获
MessageSecurityException的分支直接调用SSOClient.Close():如果触发该异常时客户端通道已经进入Faulted状态,调用Close()本身就会抛出你贴出的堆栈异常,这个二次异常没有被捕获,会直接跳出重试循环,导致重试逻辑完全失效 - 触发
CommunicationObjectFaultedException的分支没有调用Abort()释放故障通道资源:未释放的故障通道会累计连接泄漏,极端情况下会耗尽连接池,导致后续所有请求都失败 - 无退避的重试逻辑:故障触发后立刻重试,网络或服务端还没从瞬态故障中恢复,大概率会连续失败
优化方案
你的「优化尝试1」已经解决了最核心的Close()二次异常问题,还可以补充以下优化点:
MyToken Token = new MyToken (); Exception exception = null; bool TokenSet = false; int maxRetryAttempts = 3; // 可以调整为3~5次,兼顾成功率和性能 int attempts = 0; while(TokenSet == false && attempts < maxRetryAttempts) { try { Token = SSOClient.GenerateSsoToken(id.ToString(), null, null, winframe, null); TokenSet = true; exception = null; } catch (CommunicationException e) { exception = e; // 正确释放旧客户端资源 if (SSOClient.State != CommunicationState.Faulted) { SSOClient.Close(); } else { SSOClient.Abort(); } SSOClient = CreateClient(); // 增加指数退避,避免立刻重试连续失败 Thread.Sleep(100 * (int)Math.Pow(2, attempts)); } attempts++; } // 重试全部失败后做错误处理 if (!TokenSet) { // 这里可以打日志或者抛出业务异常,方便排查非瞬态的服务端故障 throw new InvalidOperationException("多次尝试获取SSO Token失败", exception); }
优化后基本可以覆盖99.9%以上的瞬态故障场景,不需要接受高频的偶发报错。这类分布式调用的异常不可能100%消除,但是做好容错处理后,出现业务侧感知的错误概率可以降到可接受的范围。
内容的提问来源于stack exchange,提问作者Richard Housham
相关产品推荐
相关产品推荐

