WCF IErrorHandler Расширение не возвращает указанный сбой

Надеюсь, что есть несколько волшебников WCF, которые могут заметить мою ошибку здесь.

Я пытаюсь настроить глобальный обработчик ошибок с помощью поведения Extension на основе IErrorHandler в службе RESTful JSON WCF. Метод оформлен так:

[OperationContract]
[WebGet(UriTemplate = "screens/info", ResponseFormat = WebMessageFormat.Json)]

Реализация IErrorHandler:

public class ErrorHandler : IErrorHandler
{
    public void ProvideFault(Exception error, 
                             MessageVersion version, 
                             ref Message fault)
    {
        var error = new JsonError 
                        { 
                            Message = error.Message, 
                            FaultCode = -1, 
                            StackTrace = error.StackTrace
                        };

        fault = Message.CreateMessage(version, 
                    "", 
                    ideaScreeningError, 
                    new DataContractJsonSerializer(
                        ideaScreeningError.GetType()));

        // tell WCF to use JSON encoding rather than default XML
        var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
        fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

        //Modify response
        var rmp = new HttpResponseMessageProperty 
                      { 
                          StatusCode = HttpStatusCode.BadRequest, 
                          StatusDescription = "Bad Request"
                      };

        fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
    }

    public bool HandleError(Exception error)
    {
        return true;
    }
}

Я могу проверить (через точки останова), что расширение вызывается и выполняется правильно. Когда я смотрю на результат вызова AJAX в браузере, я вижу, что WCF по-прежнему возвращает 500 Internal Server Error, а не сведения о сбое, которые я указал в обработчике ошибок.

Если я изменяю типы исключений, создаваемые в методе WCF, они отражаются в результате в браузере, поэтому я могу предположить, что WCF что-то делает для обработки исключения и возвращает что-то внутренне.

Как мне это остановить!?

РЕДАКТИРОВАТЬ

Я добавляю пользовательский элемент поведения:

public class ErrorBehaviorElement : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new ErrorBehavior();
    }

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

И поведение:

internal class ErrorBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint,
        EndpointDispatcher endpointDispatcher)
    {
        // clear default error handlers.  
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();

        // add the Json error handler.  
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(
            new ErrorHandler());
    }  
}

3 ответа

Решение

Проблема здесь заключается в WCF Rest Starter Kit (который я не знал, использовался, так как я не начинал этот проект), более конкретно WebServiceHost2, Я открыл ServiceHost в Reflector и нашел этот прекрасный маленький кусочек кода в OnOpening():

if (endpoint.Behaviors.Find<WebHttpBehavior>() != null)
{
    endpoint.Behaviors.Remove<WebHttpBehavior>();
    WebHttpBehavior2 item = new WebHttpBehavior2();
    // other code omitted
    endpoint.Behaviors.Add(item);
}

Как вы можете видеть, независимо от того, какое поведение вы хотите добавить в конечную точку, поскольку она наследует от WebHttpBehavior, компоненты Rest Start Kit будут захватывать ваш обработчик, удалять его и заменять его собственным.

Имейте в виду, что WebHttpBehavior2 также наследуется от WebHttBehavior, поэтому наследование от WebHttpBehavior2 в моем расширении не помогло.

Первым шагом было создание нового WebSeriveHost, который получен из WebServiceHost2 и перебор OnOpening() и перехитрить то, что у меня украл у меня Стартовый набор для отдыха:

if(endpoint.Behaviors.Find<WebHttpBehavior>() != null)
{
    endpoint.Behaviors.Remove<WebHttpBehavior>();
    var item = ErrorBehavior();
    // other code
    endpoint.Behaviors.Add(item);
}

А затем создайте новый WebServiceHostFactory, который вернул мой пользовательский тип WebServiceHost.

Не забудьте также указать ContentType ответа:

rmp.Headers[HttpResponseHeader.ContentType] = "application/json";

На основании комментариев я бы попытался удалить общий webHttpBehavior. Вы определили свое собственное поведение, полученное из webHttp. Нет никаких причин иметь два поведения webHttp в конфигурации вашей службы. Более того, поведение webHttp добавляет свой собственный обработчик ошибок, который ведет себя именно так, как вы описали. Может быть, это не поможет, но вы можете попробовать.

Другие вопросы по тегам