Пользовательский обработчик ошибок WCF для условного возврата XML или JSON?

Протокол open311 требует поддержки конечных точек в следующем формате:

  • домен /requests.xml
  • домен /requests.json

Первая конечная точка принимает запросы XML, вторая - запросы JSON.

Протокол также указывает, что ошибки должны быть возвращены в формате запроса (xml или json).

При реализации ServiceBehaviorErrorHandler я обнаружил, что невозможно определить формат запроса (xml или json) в методе ProvideFault. Все примеры либо возвращают json или xml.

Как определить формат запроса, чтобы я мог вернуть сообщение об ошибке в том же формате? Моя реализация:

    /// <summary>
/// From http://www.codeproject.com/Articles/43621/Extending-WCF-Part-I
/// </summary>
public class ExtendedServiceErrorHandler : IErrorHandler, IServiceBehavior
{
    #region IErrorHandler Members

    bool IErrorHandler.HandleError( Exception error )
    {
        return ( error is Open311Exception );
    }

    /*
     * TODO: HTTP error codes are required, but the code in the response body shouldn't necessarily match the HTTP error code, 
     * so that more specific and unique error code identifiers can be used. 
     * The HTTP error codes should always be 404 for resources that don't exist, 
     * 403 for errors because of wrong or missing api_key and basically 
     * 400 for any other error where the request can not be fulfilled as expected. 
     * Multiple errors codes and descriptions can be returned in the body (the response is an array).
     */
    void IErrorHandler.ProvideFault( Exception error, MessageVersion version, ref Message fault )
    {
        var ajaxErrors = new AjaxErrors();
        var open311Error = error as Open311Exception;
        if( null != open311Error )
        {
            ajaxErrors.Add( new AjaxError()
                {
                    Code = open311Error.Code,
                    Message = open311Error.Message
                } );
        }
        else
        {
            ajaxErrors.Add( new AjaxError()
                {
                    Code = 400,
                    Message = error.Message
                } );
        }
        var contentType = "application/json"; // TODO: how do we know?
        // WebOperationContext.Current.IncomingRequest.ContentType doesn't work
        WebContentFormat webContentFormat;
        switch( contentType )
        {
            case "application/json":
                fault = Message.CreateMessage( version, string.Empty, ajaxErrors, new DataContractJsonSerializer( ajaxErrors.GetType() ) );
                webContentFormat = WebContentFormat.Json;
                break;
            case "application/xml":
                fault = Message.CreateMessage( version, string.Empty, ajaxErrors, new DataContractSerializer( ajaxErrors.GetType() ) );
                webContentFormat = WebContentFormat.Xml;
                break;
            default:
                fault = Message.CreateMessage( version, string.Empty, ajaxErrors, new DataContractSerializer( ajaxErrors.GetType() ) );
                webContentFormat = WebContentFormat.Raw;
                break;
        }
        var wbf = new WebBodyFormatMessageProperty( webContentFormat );
        fault.Properties.Add( WebBodyFormatMessageProperty.Name, wbf );
        WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK; //  HttpStatusCode.BadRequest;
    }

    #endregion

    #region IServiceBehavior Members

    void IServiceBehavior.AddBindingParameters( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters )
    {
        // nothing to do?
    }

    void IServiceBehavior.ApplyDispatchBehavior( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase )
    {
        var errorHandler = new ExtendedServiceErrorHandler();

        foreach( ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers )
        {
            channelDispatcher.ErrorHandlers.Add( errorHandler );
        }
    }

    void IServiceBehavior.Validate( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase )
    {
        // nothing to do?
    }

    #endregion
}

1 ответ

Решение

Я верю в то, что вы ищете: http://msdn.microsoft.com/en-us/library/vstudio/ee513227(v=vs.100).aspx

Обработка ошибок веб-HTTP Windows Communication Foundation (WCF) позволяет возвращать ошибки из веб-служб WCF HTTP, которые задают код состояния HTTP, и возвращать сведения об ошибках, используя тот же формат, что и операция (например, XML или JSON).

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