WCF始终为异常返回400

时间:2012-03-13 13:26:54

标签: c# wcf rest

我有一个RESTful WCF服务,我已经实现了一个ErrorHandler,如下所示:

public class MyErrorHandler : IErrorHandler, IServiceBehavior
{
    // OMITTED: IServiceBehavior Members

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        DoSomeCustomLogging(error);
        WebOperationContext ctx = WebOperationContext.Current;
        ctx.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError;
    }           
}   
   
public class MyErrorHandlerElement : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new MyErrorHandler();
    }

    public override Type BehaviorType
    {
        get
        {
            return typeof(MyErrorHandler);
        }
    }
}
   

它像我这样挂在我的web.config中:

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="Rest">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add name ="errorHandler" type="ACME.MyErrorHandlerElement, ACME.MyErrorHandler"/>
    </behaviorExtensions>
  </extensions>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <standardEndpoints>
    <webHttpEndpoint>
      <standardEndpoint name="" faultExceptionEnabled="false" helpEnabled="false"     automaticFormatSelectionEnabled="true"  />
    </webHttpEndpoint>
  </standardEndpoints>
</system.serviceModel>

出于某种原因,如果我的服务抛出异常,则会将400返回给客户端而不是500.任何想法为什么?

2 个答案:

答案 0 :(得分:1)

您需要修改通过引用传入的错误,这不是您的常规webmethod调用。

#Region "IErrorHandler Members"
Public Function HandleError(ByVal [error] As Exception) As Boolean Implements IErrorHandler.HandleError
  Console.WriteLine("HandleError called.")
  ' Returning true indicates you performed your behavior.
  Return True
End Function

' This is a trivial implementation that converts Exception to FaultException<GreetingFault>.
Public Sub ProvideFault(ByVal [error] As Exception, ByVal ver As MessageVersion, ByRef msg As Message) Implements IErrorHandler.ProvideFault
  Console.WriteLine("ProvideFault called. Converting Exception to GreetingFault....")
  Dim fe As New FaultException(Of GreetingFault)(New GreetingFault([error].Message))
  Dim fault As MessageFault = fe.CreateMessageFault()
  msg = Message.CreateMessage(ver, fault, "http://microsoft.wcf.documentation/ISampleService/SampleMethodGreetingFaultFault")
End Sub
#End Region

MSDN Source

答案 1 :(得分:0)

有好消息和坏消息。好消息是,如果您的配置正确,您的代码将起作用。我马上就会解决这个问题。坏消息是这个解决方案可能不稳定。根据MSDN文档,ProvidFault method is not guaranteed to execute on the same thread as the service operation,因此访问类似WebOperationContext.Current的内容可能会被击中。

那就是说,以下是解决问题的方法:

您没有看到预期的结果,因为您的配置错误。您的配置正确地声明了扩展,但它并不打算声明任何端点应该使用它。在两个星号注释之间是我插入到您的配置中的修复:

<system.serviceModel>
  <!-- ****************** -->
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <errorHandler />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <!-- ****************** -->
  <extensions>
    <behaviorExtensions>
      <add name ="errorHandler" type="ACME.MyErrorHandlerElement, ACME.MyErrorHandler"/>
    </behaviorExtensions>
  </extensions>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <standardEndpoints>
    <webHttpEndpoint>
      <standardEndpoint name="" faultExceptionEnabled="false" helpEnabled="false"     automaticFormatSelectionEnabled="true"  />
    </webHttpEndpoint>
  </standardEndpoints>
</system.serviceModel>  

您可能遇到的另一个问题是您的配置已激活asp.net兼容模式。启用该模式后,我的安装行为出现问题。您的里程可能会有所不同。

最后一件事,如果尽管MSDN文档中的警告你希望继续你的方法,那么我建议你让你的IErrorHandler扩展看起来像这样:

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
    var faultEx = error as FaultException;
    bool isRest = version == MessageVersion.None;

    if (isRest && faultEx == null)
    {
        OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
        if (response.StatusCode == HttpStatusCode.BadRequest) {
            response.StatusCode = HttpStatusCode.InternalServerError;
        }
    }
}

上述代码可确保您不会意外覆盖服务操作开发人员明确设置的状态代码。它还允许开发人员抛出的WebFaultException错误与开发人员分配的任何状态代码一起传播。