WCF IErrorHandler для возврата FaultException в SOAP и WebHttpException в конечные точки POX и Json - PullRequest
16 голосов
/ 25 августа 2011

У меня есть набор веб-сервисов SOAP, которые обертывают исключения с помощью IErrorHandler, а именно:

public sealed class ErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        // don't wrap existing fault exceptions
        if ((error is FaultException)) return;

        // our basic service fault
        var businessFault = new BusinessFault { FaultMessage = error.Message, FaultReference = "Internal" };

        // Resource based faultReason
        var faultReason = new FaultReason(Properties.Resources.BusinessFaultReason);
        var faultcode = FaultCodeFactory.CreateVersionAwareSenderFaultCode(InternalFaultCodes.BusinessFailure.ToString(), Service.Namespace);

        var faultException = new FaultException<BusinessFault>(
            businessFault,
            faultReason,
            faultcode);

        // Create message fault
        var messageFault = faultException.CreateMessageFault();

        // Create message using Message Factory method
        fault = Message.CreateMessage(version, messageFault, faultException.Action);
    }
}

Я добавил дополнительные конечные точки для Json и Pox, которые работают нормально, если не происходит исключение. В случае конечной точки Json FaultException возвращается в виде XML.

Мне известно из других сообщений SO, что в случае REST мне лучше создать исключение WebHttpException:

throw new WebFaultException<BusinessFault>(detail, HttpStatusCode.BadRequest);

Или переопределить свойства ответного сообщения в ProvideFault, например:

var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

var rmp = new HttpResponseMessageProperty
{
    StatusCode = System.Net.HttpStatusCode.BadRequest,
    StatusDescription = "See fault object for more information."
};
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);

Однако в MSDN есть несколько интересных замечаний по поводу WebHttpException , а именно:

При использовании конечной точки REST WCF (WebHttpBinding и WebHttpBehavior или WebScriptEnablingBehavior) устанавливается HTTP-код состояния в ответе соответственно. Тем не менее, WebFaultException можно использовать с не-REST конечные точки и ведет себя как обычное исключение FaultException.

При использовании конечной точки REST WCF формат ответа сериализованного неисправность определяется так же, как реакция без неисправности. Для большего информацию о форматировании WCF REST см. в разделе Форматирование WCF REST.

Таким образом, можно предположить, что мне нужно преобразовать мой текущий метод ProvideFault, чтобы обеспечить новое WebHttpException (обертывание любых существующих исключений или FaultExceptions), и тогда SOAP все равно будет работать.

Кто-нибудь хотел бы попробовать, как это будет выглядеть (.Net4.0 btw)? Я хочу, чтобы один обработчик ошибок управлял ими всеми!

Ответы [ 2 ]

0 голосов
/ 08 сентября 2014

В приложении REST, над которым я работаю, я создал новый класс, производный от WebFaultException<T>, который присоединяет некоторые дополнительные данные к перехваченным исключениям служб.Вызов метода CreatingMessageFault() для экземпляра производного класса позволяет мне вернуть выбранные данные об исключениях из метода ProvideFault() обработчика ошибок как ошибку SOAP, позволяя WCF определить правильный формат сообщения.

IЯ использую webHttpBinding для привязки всех, кроме некоторых сторонних сервисов.

Редактировать: Добавлен пример кода

public class ErrorHandler : IErrorHandler, IServiceBehavior
{       
    public virtual void ProvideFault( Exception error, MessageVersion version, ref Message fault )
    {
        // Include next level of detail in message, if any.
        MyFaultException myFaultException =
            ((error is MyFaultException) &&
                ((MyFaultException)error).Detail != null)
            ? new MyFaultException(error.Message + " - " +
                    ((MyFaultException)error).Detail.Message, error)
            : new MyFaultException( error.Message, error );
        MessageFault messageFault = myFaultException.CreateMessageFault();
        fault = Message.CreateMessage( version, messageFault, myFaultException.Action );
    }
}

и

/// <summary>
/// Class used to return exception data from my WCF services.
/// </summary>
/// <remarks>
/// This class is used by a web service to pass exception data back and a
/// data object to the client. This class inherits WebFaultException, which
/// is handled specially by the WCF WebServiceHost2 service class and
/// generates a WebException on the client.
/// </remarks>
public class MyFaultException : WebFaultException<BusinessFault>
{
public class MyFaultException : WebFaultException<BusinessFault>
{
    public MyFaultException(string message)
        : this(HttpStatusCode.BadRequest, message) { }

    public MyFaultException(HttpStatusCode statusCode, string message)
        : base(new BusinessFault(message), statusCode) { }
}

затем в вашем сервисе вы можете выбросить исключение для передачи данных о сбоях вашему клиенту:

        try
        {
            // Successful operation proceeds normally.
        }
        catch (ApplicationException e)
        {
            // Failure generates MyFaultException.
            throw new MyFaultException("Operation failed with " + e.Message);
        }
0 голосов
/ 11 марта 2013

У меня сложилось впечатление, что использование webHttpBinding - это способ получить "все в одном" функциональность JSON / POX / SOAP, а не использовать отдельные привязки для каждого (то есть wsHttpBinding, basicHttpBinding так далее.). Так не могли бы вы просто выбросить WebHttpException, а затем получить все необходимые сведения об ошибках независимо от технологии?

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