2012-03-13 2 views
0

у меня есть RESTful службы WCF, и я осуществил ErrorHandler, такие как:WCF всегда возвращается 400 для исключения

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. Любые идеи почему?

+0

Ваш вебконфигурация отсутствует, пожалуйста, обновите –

+0

в файле конфигурации, введите MyErrorHandlerElement - не должно быть MyErrorHandler? – Eric

+0

Eric, в типе, первым элементом является ErrorHandlerElement (я обновил свой пример, чтобы включить его), а второй - имя сборки. – Bullines

ответ

1

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

#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

При реализации этого теперь я возвращаю 200, когда исключение вызывается в бизнес-компоненте, вызванном методом службы, что также не является идеальным. Однако это нормально (возврат 500), когда исключение выбрасывается самим методом службы. – Bullines

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; 
     } 
    } 
} 

Приведенный выше код гарантирует, что вы не 't случайно переопределить код состояния, который был явно задан разработчиком операции службы. Он также допускает ошибки WebFaultException, которые разработчик может инициировать с помощью того, какой код статуса был назначен разработчиком.

Смежные вопросы