我已经实现了IErrorHandler来处理在我的restful WCF服务的构造函数中抛出的授权异常.捕获常规异常时,我的自定义类型按预期返回,但ContentType标头不正确.
HTTP/1.1 500 Internal Server Error Content-Type: application/xml; ... {"ErrorMessage":"Error!"}
但是,当错误处理程序尝试返回401 Unauthorized http状态代码时,消息正文将被覆盖为默认类型,但ContentType标头应该是它应该的样本.
HTTP/1.1 401 Unauthorized Content-Type: application/json; ... {"Message":"Authentication failed.","StackTrace":null,"ExceptionType":"System.InvalidOperationException"}
显然这里有些不对劲,但我不确定是什么.
如何实现IErrorHandler,使其在json中使用正确的标头返回我的自定义类型?
BaseDataResponseContract对象:
[Serializable] [DataContract( Name = "BaseDataResponseContract" )] public class BaseDataResponseContract { [DataMember] public string ErrorMessage { get; set; } } // end
这是我想要返回的对象.我的应用程序中的所有其他对象都继承自此对象.当抛出异常时,我们真正关心的是http状态代码和错误消息.
IErrorHandler实现(为简洁起见,未显示日志记录):
namespace WebServices.BehaviorsAndInspectors { public class ErrorHandler : IErrorHandler { public bool HandleError(Exception error) { return true; } // end public void ProvideFault(Exception ex, MessageVersion version, ref Message fault) { // Create a new instance of the object I would like to return with a default message var baseDataResponseContract = new BaseDataResponseContract { ErrorMessage = "Error!" }; // Get the outgoing response portion of the current context var response = WebOperationContext.Current.OutgoingResponse; // Set the http status code response.StatusCode = HttpStatusCode.InternalServerError; // If the exception is a specific type change the default settings if (ex.GetType() == typeof(UserNotFoundException)) { baseDataResponseContract.ErrorMessage = "Invalid Username!"; response.StatusCode = HttpStatusCode.Unauthorized; } // Create the fault message that is returned (note the ref parameter) fault = Message.CreateMessage(version, "", baseDataResponseContract, new DataContractJsonSerializer(typeof(BaseDataResponseContract))); // Tell WCF to use JSON encoding rather than default XML var webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json); fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty); // Add ContentType header that specifies we are using json var httpResponseMessageProperty = new HttpResponseMessageProperty(); httpResponseMessageProperty.Headers[HttpResponseHeader.ContentType] = "application/json"; fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponseMessageProperty); } // end } // end class } // end namespace
IServiceBehavior实施:
namespace WebServices.BehaviorsAndInspectors { public class ErrorHandlerExtensionBehavior : BehaviorExtensionElement, IServiceBehavior { public override Type BehaviorType { get { return GetType(); } } protected override object CreateBehavior() { return this; } private IErrorHandler GetInstance() { return new ErrorHandler(); } void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collectionendpoints, BindingParameterCollection bindingParameters) { } // end void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { var errorHandlerInstance = GetInstance(); foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) { dispatcher.ErrorHandlers.Add(errorHandlerInstance); } } void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end } // end class } // end namespace
Web.Config中:
....
最后,我在使用WebFaultException时看到了类似的行为.我的想法是,这是一些深埋的.Net恶作剧的结果.我选择实现IErrorHandler,以便我可以捕获任何其他可能无法处理的异常.
参考:
https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx
http://www.brainthud.com/cards/5218/25441/which-four-behavior-interfaces-exist-for-interacting-with-a-service-or-client-description-what-methods-do-they-落实和
其他例子:
IErrorHandler似乎没有处理我在WCF中的错误..任何想法?
如何使用非OK http代码使自定义WCF错误处理程序返回JSON响应?
如何为HttpClient请求设置Content-Type标头?