首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WCF: FaultContract集但不导致FaultException<T>在REST服务中被捕获

WCF: FaultContract集但不导致FaultException<T>在REST服务中被捕获
EN

Stack Overflow用户
提问于 2012-08-18 01:25:38
回答 2查看 4.2K关注 0票数 2

我刚刚从WCF开始,并试图验证支持JSON和XML的WCF rest服务中的故障处理。我的测试服务生成一个错误,但无论我如何尝试,我都无法让我的当事人获取故障的详细信息(而且行为会根据请求格式和http状态代码而有所不同):

我的测试服务生成的错误如下:

代码语言:javascript
复制
public Data GetResponse()
{
    throw new WebFaultException<ErrorDetails>(
        new ErrorDetails {ErrorMessage = "Server Config Value not set"},
        HttpStatusCode.OK
        );
}

这是通过电线相当合理地发送:

代码语言:javascript
复制
{"ErrorMessage":"Server Config Value not set"}

和:

代码语言:javascript
复制
<ErrorDetails xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <ErrorMessage>Server Config Value not set</ErrorMessage>
</ErrorDetails>

我的客户端是用FaultContract定义的

代码语言:javascript
复制
[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:

请求回复:请求完成按一个键退出.

客户端代码按照正确的顺序捕获异常:

代码语言:javascript
复制
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,我需要做什么?

注意:要旨应该是完全可编译和可运行的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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

解决方案

经过相当多的研究后,我的找到一个博主建议创建一个助手类,从嵌入在异常对象中的响应流中提取信息。以下是他的实施情况:

代码语言:javascript
复制
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;
  }
}
票数 4
EN

Stack Overflow用户

发布于 2014-02-13 10:50:53

我用过这个:

代码语言:javascript
复制
 try
            {
              //wcf service call
            }
            catch (FaultException ex)
            {
               throw new Exception( (ex as WebFaultException<MyContractApplicationFault>).Detail.MyContractErrorMessage );                
            }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12015067

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档