我刚刚从WCF开始,并试图验证支持JSON和XML的WCF rest服务中的故障处理。我的测试服务生成一个错误,但无论我如何尝试,我都无法让我的当事人获取故障的详细信息(而且行为会根据请求格式和http状态代码而有所不同):
我的测试服务生成的错误如下:
public Data GetResponse()
{
throw new WebFaultException<ErrorDetails>(
new ErrorDetails {ErrorMessage = "Server Config Value not set"},
HttpStatusCode.OK
);
}这是通过电线相当合理地发送:
{"ErrorMessage":"Server Config Value not set"}和:
<ErrorDetails xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ErrorMessage>Server Config Value not set</ErrorMessage>
</ErrorDetails>我的客户端是用FaultContract定义的
[OperationContract]
[WebInvoke(
UriTemplate="/response",
Method="GET",
RequestFormat = WebMessageFormat.Xml, // or .Json
ResponseFormat = WebMessageFormat.Xml // or .Json
)]
[FaultContract(typeof(ErrorDetails), Namespace="")]
Data GetResponse();以下是(格式/状态代码)的完整错误消息:
XML/冲突:
请求响应CommunicationException:远程服务器返回一个意外响应:(409)冲突。,System.Collections.ListDictionary内部,System.ServiceModel.ProtocolException按一个键退出.
和XML/OK:
请求响应异常:无法用根名称'ErrorDetails‘和根命名空间’(用于操作'GetResponse‘和d契约('IClient','’)反序列化XML主体。确保将与XML相对应的类型添加到服务的知情n类型集合中。System.Collections.ListDictionaryInternal按一个键退出.
和JSON/冲突:
请求响应CommunicationException:远程服务器返回一个意外响应:(409)冲突。,System.Collections.ListDictionary内部,System.ServiceModel.ProtocolException按一个键退出.
和JSON/OK:
请求回复:请求完成按一个键退出.
客户端代码按照正确的顺序捕获异常:
try
{
Console.WriteLine("Requesting response");
Console.WriteLine("Response: " + client.GetResponse().Message);
Console.WriteLine("Request complete");
}
// sanity check, just in case...
catch (WebFaultException<ErrorDetails> ex)
{
Console.WriteLine("WebFaultException<ErrorDetails>: " + ex.Detail.ErrorMessage + ", " + ex.Reason);
}
catch (FaultException<ErrorDetails> ex)
{
Console.WriteLine("FaultException<ErrorDetails>: " + ex.Detail.ErrorMessage + ", " + ex.Reason);
}
catch (FaultException ex)
{
Console.WriteLine("FaultException: " + ex.Message + ", " + ex.Reason);
}
catch (CommunicationException ex)
{
Console.WriteLine("CommunicationException: " + ex.Message + ", " + ex.Data + ", " + ex.GetType().FullName);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message + ", " + ex.Data);
}如果要抛出FaultException<ErrorDetails>并访问ErrorDetails,我需要做什么?
注意:要旨应该是完全可编译和可运行的。
发布于 2012-08-30 22:20:39
在WCF REST客户端( WCF version 4.0)服务中,不可能使用故障/FaultContract作为错误处理机制:
WCF列表中的每个一根线:
在WCF服务中,没有SOAP消息,因此不能将FaultException返回给客户端。实际上,适当的状态代码作为HTTP报头返回给请求者,允许请求者确定调用的结果。
来自一个StackOverflow邮政
故障是SOAP协议的一部分,在REST方案中不可用。
选项被认为是
FaultContract - FaultContractAttribute适用于SOAP信封,但不适用于works服务。如果您将XML发送到已格式化为SOAP信封的XML,则可能会使其正常工作,但您没有使用合理的自定义错误消息。
IErrorHandler --快速阅读文档表明这是针对服务的,并认为这是一个新手错误:“允许实现者控制返回给调用方的错误消息,并可选择地执行自定义错误处理,例如日志记录。”
信息检查器 -- AfterReceiveRequest不执行,因为首先抛出CommunicationException。
解决方案
经过相当多的研究后,我的找到一个博主建议创建一个助手类,从嵌入在异常对象中的响应流中提取信息。以下是他的实施情况:
public static void HandleRestServiceError(Exception exception, Action<TServiceResult> serviceResultHandler, Action<TServiceFault> serviceFaultHandler = null, Action<Exception> exceptionHandler = null)
{
var serviceResultOrServiceFaultHandled = false;
if (exception == null) throw new ArgumentNullException("exception");
if (serviceResultHandler == null) throw new ArgumentNullException("serviceResultHandler");
// REST uses the HTTP procol status codes to communicate errors that happens on the service side.
// This means if we have a teller service and you need to supply username and password to login
// and you do not supply the password, a possible scenario is that you get a 400 - Bad request.
// However it is still possible that the expected type is returned so it would have been possible
// to process the response - instead it will manifest as a ProtocolException on the client side.
var protocolException = exception as ProtocolException;
if (protocolException != null)
{
var webException = protocolException.InnerException as WebException;
if (webException != null)
{
var responseStream = webException.Response.GetResponseStream();
if (responseStream != null)
{
try
{
// Debugging code to be able to see the reponse in clear text
//SeeResponseAsClearText(responseStream);
// Try to deserialize the returned XML to the expected result type (TServiceResult)
var response = (TServiceResult) GetSerializer(typeof(TServiceResult)).ReadObject(responseStream);
serviceResultHandler(response);
serviceResultOrServiceFaultHandled = true;
}
catch (SerializationException serializationException)
{
// This happens if we try to deserialize the responseStream to type TServiceResult
// when an error occured on the service side. An service side error serialized object
// is not deserializable into a TServiceResult
// Reset responseStream to beginning and deserialize to a TServiceError instead
responseStream.Seek(0, SeekOrigin.Begin);
var serviceFault = (TServiceFault) GetSerializer(typeof(TServiceFault)).ReadObject(responseStream);
if (serviceFaultHandler != null && serviceFault != null)
{
serviceFaultHandler(serviceFault);
serviceResultOrServiceFaultHandled = true;
}
else if (serviceFaultHandler == null && serviceFault != null)
{
throw new WcfServiceException<TServiceFault>() { ServiceFault = serviceFault };
}
}
}
}
}
// If we have not handled the serviceResult or the serviceFault then we have to pass it on to the exceptionHandler delegate
if (!serviceResultOrServiceFaultHandled && exceptionHandler != null)
{
exceptionHandler(exception);
}
else if (!serviceResultOrServiceFaultHandled && exceptionHandler == null)
{
// Unable to handle and no exceptionHandler passed in throw exception to be handled at a higher level
throw exception;
}
}发布于 2014-02-13 10:50:53
我用过这个:
try
{
//wcf service call
}
catch (FaultException ex)
{
throw new Exception( (ex as WebFaultException<MyContractApplicationFault>).Detail.MyContractErrorMessage );
}https://stackoverflow.com/questions/12015067
复制相似问题