WCF всегда возвращает 400 для исключений - PullRequest
0 голосов
/ 13 марта 2012

У меня есть служба 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 ]

1 голос
/ 13 марта 2012

Вам нужно изменить ошибку, которая передается по ссылке, это не ваш обычный вызов веб-метода.

#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

0 голосов
/ 07 июля 2015

Есть хорошие и плохие новости.Хорошей новостью является то, что ваш код работал бы, если бы ваша конфигурация была правильной.Я предоставлю исправление через минуту.Плохая новость заключается в том, что это решение может быть нестабильным.Согласно документации MSDN, метод ProvidFault не гарантированно выполняется в том же потоке, что и операция службы , и, таким образом, доступ к чему-то вроде 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, выдаваемым разработчиком, распространяться с любым кодом состояния, назначенным разработчиком.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...