xmlasp.net-web-apiasp.net-corecontent-negotiationhttp-accept-header

ASPNetCore API Content negotiation not working


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.


Solution

  • 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!