Jim
Jim

Reputation: 583

Web API exceptions show as XML in Chrome

I'm learning Web Api and have bumped into the following issue. Similar to this question.

My exceptions are still returning as XML in Chrome, but JSON in IE. The exceptions are thrown as XML when inheriting from the ODataController but are correctly thrown as JSON when inheriting from ApiController.

My WebApiConfig class:

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services
    config.Filters.Add(new NotImplementedExceptionFilterAttribute());
    config.Filters.Add(new MethodAttributeExceptionHandling());

    config.Services.Replace(typeof(IHttpActionInvoker), new CustomApiControllerActionInvoker());

    // Web API routes
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<EventType>("EventTypes"); 

    config.Routes.MapODataRoute("ODataRoutes", "api", builder.GetEdmModel());

    //Route Configuration
    config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}"
    );


    var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
    config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);

}

I have a CustomApiControllerActionInvoker verbatim from: http://www.codeproject.com/Articles/733512/Exception-Handling-in-WebAPI

My TestController inheriting from ApiController:

public HttpResponseMessage GetGlobalErrorMessage()
{
    int i = 0;
    var val = 10 / i;
    return new
        HttpResponseMessage(HttpStatusCode.OK);
}

returns JSON in Chrome:

{
"Message": "Oops some internal Exception. Please contact your administrator",
"ErrorCode": 500
}

However, if I inherit from ODataController with similar code:

[Queryable]
public IQueryable<EventType> Get()
{
    int i = 0;
    var val = 10 / i;
    return _repo.EventTypes();
}

I'm returned XML from the exception in Chrome:

<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code/>
<m:message xml:lang="en-US">
Oops some internal Exception. Please contact your administrator
</m:message>
</m:error>

Summary:

How do I force consistent content types for payloads as well as exceptions, still allowing flexibility for native content negotiation using OData Web Api?

Upvotes: 0

Views: 717

Answers (2)

DATEx2
DATEx2

Reputation: 3503

As @Kiran said above, here is a working example

[ODataFormattingOnlyJSON]
public class BaseODataController
    : ODataController
{
}
public class ODataFormattingOnlyJSONAttribute : ODataFormattingAttribute, IControllerConfiguration
{
    void IControllerConfiguration.Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        base.Initialize(controllerSettings, controllerDescriptor);
        //remove all the dirty non json formatters
        var remove = controllerSettings.Formatters.Where(m => !m.SupportedMediaTypes.Any(t => t.MediaType.IndexOf("json", StringComparison.OrdinalIgnoreCase) >= 0)).ToArray();
        foreach (var item in remove)
        {
            controllerSettings.Formatters.Remove(item);
        }
    }
}

Then all your controllers inherit from BaseODataController

Upvotes: 1

Kiran
Kiran

Reputation: 57989

The difference in response formats between these browsers is due to the kind of Accept headers that they send. Depending on Accept header, Web API runs content-negotiation and returns the appropriate response. ODataController is special in that it does not use the formatters that regular ApiController uses. Instead ODataController has a Per-Controller Configuration attribute called ODataFormattingAttribute from which you can derive to build a custom list of formatters through its CreateODataFormatters method and use this attribute on all your ODataControllers.

Upvotes: 0

Related Questions