使用WCF Client调用SOAP服务时无法读取HTTP Statuscode
在.NET 6.0中获取SOAP服务调用的HTTP状态码
问题背景
我们基于.NET 6.0环境,通过以下代码调用SOAP服务:
public Task<MyResponseModel> SendAsync(MyRequestModel request) { var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport) { OpenTimeout = TimeSpan.FromSeconds(30), SendTimeout = TimeSpan.FromSeconds(10), }; var endpointAddress = new EndpointAddress("https://example.com/"); ChannelFactory<IWcfClient> channelFactory = null; try { channelFactory = new ChannelFactory<IWcfClient>(binding, endpointAddress); channelFactory.Endpoint.EndpointBehaviors.Add(new InspectMessageBehavior()); IWcfClient channel = channelFactory.CreateChannel(); return channel.SendItemAsync(request); } catch (Exception) { if (channelFactory != null) channelFactory.Abort(); throw; } }
当SOAP服务端出现错误时,返回的错误信息完全一致,无法针对不同业务错误做流程处理,唯一的差异是HTTP状态码,但我们始终无法读取到这个状态码。第三方服务提供方不愿修改此行为,我们已经尝试过以下方法但均无效:
- 直接读取异常信息
- 实现
IEndpointBehavior尝试读取状态码 - 捕获
ChannelFactory的Faulted、Closed等事件(Faulted事件未触发)
解决方案
可以通过自定义IClientMessageInspector,从WCF的HttpResponseMessageProperty中提取HTTP状态码,具体实现如下:
1. 实现自定义消息检查器
这个检查器会在收到服务回复后,提取HTTP状态码并保存:
public class HttpStatusCodeInspector : IClientMessageInspector { public int? HttpStatusCode { get; private set; } public object BeforeSendRequest(ref Message request, IClientChannel channel) { return null; } public void AfterReceiveReply(ref Message reply, object correlationState) { if (reply.Properties.TryGetValue(HttpResponseMessageProperty.Name, out var property)) { var httpResponse = property as HttpResponseMessageProperty; HttpStatusCode = (int)httpResponse.StatusCode; } } }
2. 实现对应的EndpointBehavior
用于将检查器注入到WCF客户端的运行时:
public class HttpStatusCodeBehavior : IEndpointBehavior { public HttpStatusCodeInspector Inspector { get; } = new HttpStatusCodeInspector(); public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(Inspector); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
3. 修改调用代码,获取状态码
在调用SOAP服务时,通过自定义Behavior获取状态码,即使发生异常也能拿到:
public async Task<MyResponseModel> SendAsync(MyRequestModel request) { var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport) { OpenTimeout = TimeSpan.FromSeconds(30), SendTimeout = TimeSpan.FromSeconds(10), }; var endpointAddress = new EndpointAddress("https://example.com/"); ChannelFactory<IWcfClient> channelFactory = null; HttpStatusCodeBehavior statusCodeBehavior = null; try { channelFactory = new ChannelFactory<IWcfClient>(binding, endpointAddress); statusCodeBehavior = new HttpStatusCodeBehavior(); channelFactory.Endpoint.EndpointBehaviors.Add(statusCodeBehavior); IWcfClient channel = channelFactory.CreateChannel(); var response = await channel.SendItemAsync(request); // 成功时也可以获取状态码 var successStatusCode = statusCodeBehavior.Inspector.HttpStatusCode; return response; } catch (Exception) { if (channelFactory != null) channelFactory.Abort(); // 异常时读取状态码,根据状态码做业务处理 if (statusCodeBehavior?.Inspector.HttpStatusCode.HasValue == true) { var errorStatusCode = statusCodeBehavior.Inspector.HttpStatusCode.Value; // 示例:根据不同状态码执行不同逻辑 // switch (errorStatusCode) // { // case 400: // // 处理参数错误 // break; // case 500: // // 处理服务内部错误 // break; // } } throw; } }
原理说明
WCF在处理HTTP协议的SOAP调用时,会将底层HTTP响应的信息封装到HttpResponseMessageProperty中,这个属性可以从回复消息的Properties集合中取出。自定义的IClientMessageInspector会在收到服务回复后执行AfterReceiveReply方法,此时就能提取出HTTP状态码,无论服务返回成功还是SOAP错误,这个属性都会被正确填充。
内容的提问来源于stack exchange,提问作者Koen
相关产品推荐
相关产品推荐

