WCF中IErrorHandler无法处理请求体序列化错误的解决问询
解决WCF WebHttpBinding下请求体JSON格式错误时无法返回自定义JSON错误的问题
问题根源
当请求体JSON格式错误时,WCF会在消息调度的早期阶段(自定义IErrorHandler介入之前)触发NetDispatcherFaultException,此时WCF默认的错误处理机制会优先返回HTML格式的400错误页,导致自定义错误处理器的逻辑被绕过。
解决方案
通过实现自定义消息格式化器,提前捕获JSON反序列化阶段的错误,将其转为可被IErrorHandler处理的异常,确保最终返回JSON格式的错误响应。
步骤1:实现自定义消息格式化器
替换默认的JSON格式化器,在反序列化请求体时捕获格式错误:
public class CustomJsonDispatchFormatter : IDispatchMessageFormatter { private readonly IDispatchMessageFormatter _originalFormatter; private readonly Type _requestType; public CustomJsonDispatchFormatter(IDispatchMessageFormatter originalFormatter, Type requestType) { _originalFormatter = originalFormatter; _requestType = requestType; } public void DeserializeRequest(Message message, object[] parameters) { try { _originalFormatter.DeserializeRequest(message, parameters); } catch (Exception ex) { // 将JSON格式错误转为自定义FaultException,确保IErrorHandler能捕获 throw new FaultException<CustomMsg>( new CustomMsg { code = "400", msg = $"请求体JSON格式错误:{ex.Message}" }); } } public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) { return _originalFormatter.SerializeReply(messageVersion, parameters, result); } }
步骤2:实现自定义Web行为,替换格式化器
创建自定义WebHttpBehavior,将默认格式化器替换为我们的自定义实现:
public class CustomJsonBehavior : WebHttpBehavior { protected override IDispatchMessageFormatter GetRequestDispatchFormatter( OperationDescription operationDescription, ServiceEndpoint endpoint) { var originalFormatter = base.GetRequestDispatchFormatter(operationDescription, endpoint); // 获取请求参数类型,传入自定义格式化器 var requestType = operationDescription.Messages[0].Body.Parts.FirstOrDefault()?.Type; return requestType != null ? new CustomJsonDispatchFormatter(originalFormatter, requestType) : originalFormatter; } }
步骤3:配置服务端点应用自定义行为
在服务宿主初始化时,给WebHttpBinding端点添加自定义行为:
using (var host = new ServiceHost(typeof(MyService))) { var webBinding = new WebHttpBinding(); var endpoint = host.AddServiceEndpoint(typeof(IMyService), webBinding, ""); // 替换默认WebHttpBehavior为自定义实现 endpoint.Behaviors.Remove<WebHttpBehavior>(); endpoint.Behaviors.Add(new CustomJsonBehavior()); host.Open(); Console.WriteLine("服务已启动"); Console.ReadLine(); }
步骤4:调整IErrorHandler处理自定义FaultException
修改ProvideFault方法,优先处理自定义FaultException,确保返回正确的JSON格式:
public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { CustomMsg errorResponse; if (error is FaultException<CustomMsg> customFault) { errorResponse = customFault.Detail; } else { // 处理其他通用异常 errorResponse = new CustomMsg { code = "99", msg = $"服务器内部错误:{error.Message}" }; } // 构造JSON格式的响应消息 fault = Message.CreateMessage(version, "", errorResponse, new DataContractJsonSerializer(typeof(CustomMsg))); // 设置消息格式为JSON var bodyFormatProp = new WebBodyFormatMessageProperty(WebContentFormat.Json); fault.Properties.Add(WebBodyFormatMessageProperty.Name, bodyFormatProp); // 设置HTTP响应头和状态码(保持需求的200) var responseProp = new HttpResponseMessageProperty { StatusCode = HttpStatusCode.OK }; responseProp.Headers[HttpResponseHeader.ContentType] = "application/json"; fault.Properties.Add(HttpResponseMessageProperty.Name, responseProp); }
原理说明
通过自定义消息格式化器,我们把原本在WCF消息调度早期发生的JSON格式错误,提前捕获并转为可被IErrorHandler处理的FaultException,这样自定义错误处理器就能完全接管错误响应逻辑,返回符合需求的JSON格式错误对象,同时保持HTTP 200状态码。
内容的提问来源于stack exchange,提问作者Yvonne Lin
相关产品推荐
相关产品推荐

