WCF IErrorHandler Расширение не возвращает указанный сбой - PullRequest
2 голосов
/ 13 сентября 2010

Надеюсь, есть несколько волшебников 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 что-то делает для обработки исключения и возвращает что-то внутренне.

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

EDIT

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

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 ]

5 голосов
/ 15 сентября 2010

Проблема здесь заключается в 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(), и повторно взломал то, что у меня украл у меня Rest Starter Kit:

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

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

0 голосов
/ 14 сентября 2010

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

0 голосов
/ 14 сентября 2010

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

rmp.Headers[HttpResponseHeader.ContentType] = "application/json";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...