.NET Core无SoapException时,如何获取WCF服务的异常XML?
在.NET Core中捕获SOAP服务异常并读取异常XML
原问题:在.NET Framework中,我可通过以下代码捕获SoapException并读取异常XML:
try { // soap call here } catch (System.Web.Services.Protocols.SoapException soapEx) { var msg = soapEx.Message; var txt = soapEx.Detail.InnerText; }在.NET Core中,我使用svcutil将WSDL生成代码,通过编程方式构建EndpointAddress和BasicHttpsBinding调用客户端,但无法访问SoapException,请问该如何获取异常XML?
解决方案
在.NET Core/.NET 5+生态里,System.Web.Services.Protocols.SoapException已经被移除了,不过我们有两种常用的方式来获取SOAP异常的XML内容,亲测好用:
方法1:捕获FaultException解析异常细节
svcutil生成的客户端会把服务抛出的SOAP Fault包装成FaultException(如果服务定义了强类型错误详情,就是FaultException<T>),你可以通过它来获取消息和XML细节:
try { // 初始化你的SOAP客户端并调用方法 var binding = new BasicHttpsBinding(); var endpoint = new EndpointAddress("你的服务地址"); using var client = new GeneratedSoapClient(binding, endpoint); await client.YourServiceOperationAsync(); } catch (FaultException faultEx) { // 获取Fault的提示消息 var errorMessage = faultEx.Message; // 读取SOAP Fault里的Detail节点XML var messageFault = faultEx.CreateMessageFault(); if (messageFault.HasDetail) { var detailXml = messageFault.GetReaderAtDetailContents().ReadOuterXml(); // 这里就拿到了异常的XML内容,按需处理即可 } } catch (FaultException<YourDefinedFaultType> typedFault) { // 如果服务有定义强类型的错误对象,直接用这个泛型捕获,更方便 var faultDetail = typedFault.Detail; // 可以直接访问faultDetail的属性,不用手动解析XML }
方法2:用消息拦截器获取完整SOAP响应
如果需要拿到完整的原始SOAP响应XML(包括整个Envelope结构),可以自定义一个客户端消息拦截器来捕获响应内容:
- 先实现
IClientMessageInspector来保存响应:
public class SoapResponseCaptureInspector : IClientMessageInspector { public string RawSoapResponse { get; private set; } public object BeforeSendRequest(ref Message request, IClientChannel channel) { return null; // 不需要处理请求,返回null即可 } public void AfterReceiveReply(ref Message reply, object correlationState) { // 把响应消息复制一份,避免影响后续处理 var messageBuffer = reply.CreateBufferedCopy(int.MaxValue); // 将消息转为字符串,就是完整的SOAP XML RawSoapResponse = messageBuffer.CreateMessage().ToString(); // 重置消息,让客户端能正常处理后续流程 reply = messageBuffer.CreateMessage(); } }
- 再创建一个行为类把拦截器加到客户端上:
public class SoapResponseCaptureBehavior : IEndpointBehavior { private readonly SoapResponseCaptureInspector _inspector; public SoapResponseCaptureBehavior(SoapResponseCaptureInspector inspector) { _inspector = inspector; } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { // 把拦截器添加到客户端的消息检查器列表里 clientRuntime.ClientMessageInspectors.Add(_inspector); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
- 最后在客户端里使用这个拦截器:
var responseInspector = new SoapResponseCaptureInspector(); var binding = new BasicHttpsBinding(); var endpoint = new EndpointAddress("你的服务地址"); using var client = new GeneratedSoapClient(binding, endpoint); // 把自定义行为添加到客户端的Endpoint上 client.Endpoint.Behaviors.Add(new SoapResponseCaptureBehavior(responseInspector)); try { await client.YourServiceOperationAsync(); } catch (Exception) { // 不管是什么异常,都能拿到完整的SOAP响应XML var fullSoapXml = responseInspector.RawSoapResponse; // 解析这个XML就能拿到所有异常信息了 }
小提示
- 如果服务返回的是标准的SOAP Fault,用
FaultException的方式足够,代码更简洁。 - 拦截器方式适合调试场景,或者需要处理非标准Fault的情况,能拿到最原始的响应内容。
内容的提问来源于stack exchange,提问作者aherrick
相关产品推荐
相关产品推荐

