ASPNetCore API Content negotiation not working
Asked Answered
B

1

12

I'm trying to get my api set up so it will respond with with XML or JSON depending upon the Accept header.

I'm following the tutorial by Shawn W: https://wildermuth.com/2016/03/16/Content_Negotiation_in_ASP_NET_Core

It says to add a package to: "Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final"

But I couldn't find it so instead installed: Microsoft.AspNetCore.Mvc.Formatters.Xml

He says to add this to the config services section in Startup:

        // Add framework services.
        services
            .AddMvc(options => {
                options.RespectBrowserAcceptHeader = true;
                options.InputFormatters.Add(new XmlSerializerInputFormatter());
                options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
            }).AddJsonOptions(options => {
                // Force Camel Case to JSON
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

Then the browser is automatically meant to receive XML because by default it uses Accept: text/xml header, I don't get XML in my browser or by using postman. I get Json no matter what I set Accept header to.

I've tried putting [Produces("application/xml")] on my controller and it returns a blank 200 OK page.

How do I get my api to return Json by default, or XML if Accept is present?

Edit 1:

I'm using this as my http get code:

    [HttpGet]
    public IActionResult Get() {
        var invoices = context.Invoices.ToList();
        var mappedInvoices = mapper.Map<List<DomainModels.Invoice>, List<Invoice>>(invoices);
        return Ok(mappedInvoices);
    }

And I'm trying to return this DTO:

public class Invoice : TrackedObject {

    public DateTime Date { get; set; }

    public decimal Total { get; set; }

    public string OrderNumber { get; set; }


    public PaymentType? PaymentType { get; set; }

    public ICollection<InvoiceItem> Items { get; set; }
}
public enum PaymentType {
    Cheque,
    Cash,
    Card,
    Account
}

Edit 2:

If I swap out this:

 // Add framework services.
        services
            .AddMvc(options => {
                options.RespectBrowserAcceptHeader = true;
                options.InputFormatters.Add(new XmlSerializerInputFormatter());
                options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
            }).AddJsonOptions(options => {
                // Force Camel Case to JSON
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

and replace with the below:

        services.AddMvc().AddXmlSerializerFormatters();

And then put [Produces("application/xml")] above my get method I get a 406 Not Acceptable response.

Basting answered 7/3, 2017 at 16:44 Comment(2)
You should add the XML serializers with services.AddMvc().AddXmlSerializerFormatters();, it's a bit easier. I had a similar issue before, the reason then was the object I was returning. Could you show what kind of data structure you are returning?Kraigkrait
@Kraigkrait Swapped out my services.AddMvc entirely for yours and it' still returning JSON!Basting
B
15

I finally found the correct setup to return JSON and XML via accept headers.

To get your web API controllers to return JSON or XML (JSON by default) you need your services configuration to look like this:

// Add framework services.
services
    .AddMvc(options => {
        options.RespectBrowserAcceptHeader = true;
    })
    //support application/xml
    .AddXmlDataContractSerializerFormatters()
    //support application/json
    .AddJsonOptions(options => {
        // Force Camel Case to JSON
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    });

Pretty simple when you know how! There is so much incorrect documentation laying around at the minute!

Basting answered 8/3, 2017 at 10:32 Comment(1)
Still pretty unclear why AddXmlSerializerFormatters() doesn't work. I experienced the same misbehavior on .NET 5.0.Jermayne

© 2022 - 2024 — McMap. All rights reserved.