29

I have the following simple Web API controller:

    // GET: api/customers
    [HttpGet]
    public async Task<IActionResult> Get()
        {
        var customers = await uow.Users.GetAllAsync();
        var dto = customers.Select(p => new CustomerDto {Id = p.Id, Email = p.Email, UserName = p.UserName});
        return Ok(dto); // IEnumerable<CustomerDto>
        }

In Postman, I'm setting the Accept header to application/xml, but no matter what I try, I can only get JSON data back.

Postman screen shot

I read somewhere that in order to get XML, I must add [DataContract] and [DataMember] attributes to my DTO, which now looks like this:

[DataContract]
public class CustomerDto
    {
    [DataMember]
    public string Id { get; set; }

    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    [DataMember]
    public string Email { get; set; }

    [Required]
    [Display(Name = "Login Name")]
    [DataMember]
    public string UserName { get; set; }
    }

I've been at it several hours now and I'm just not seeing why it doesn't work. I've tried:

  • Making the action method synchronous and asynchronous

  • Returning the data directly, and setting the return type to IEnumerable<CustomerDto>

  • Converting the collection to an array instead of a list

  • Returning an IActionResult

  • Returning a single item, instead of a collection

  • I've verified that the Accept header is showing up in the request by examining it in the debugger.

  • Lots of "Googling with Bing" and reading various blogs

  • Creating a new WebAPI project from the template and seeing if there is any inspiration there (not really).

    I expect it's simple, but I can't see it...

3
  • 1
    Could you show you registered your Xml formatters in Startup.cs? Commented Jul 11, 2016 at 21:29
  • Have you ever configured formatters? Commented Jul 11, 2016 at 21:31
  • Of course that was the problem. Last time I used a WebAPI that was all enabled by default. I forgot about the new lightweight pay-as-you-go approach in ASP.Net 5! The extension methods were not really very discoverable, though, either. I had to know to install another NuGet package then dot into the AddMvc() call. Commented Jul 11, 2016 at 23:25

8 Answers 8

33

Xml formatters are part of a separate package: Microsoft.AspNetCore.Mvc.Formatters.Xml

Add the above package and update your startup.cs like below:

services
    .AddMvc()
    .AddXmlDataContractSerializerFormatters();

OR

services
    .AddMvc()
    .AddXmlSerializerFormatters();
Sign up to request clarification or add additional context in comments.

9 Comments

Ahh... I wondered if it might be something like that. Shame the documentation is a bit unfinished. Wasn't the XML formatter enabled by default in MVC5?
Yes it was in MVC5 but this was changed very early on in ASP.NET 5
@TimLong: You would have to look for that information in MSDN probably.
These methods don't seem to exist with the latest version of asp.net core!
In mvc 1.1 I needed: services.AddMvc(options => {options.RespectBrowserAcceptHeader = true;}).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters(); or it would always give me json
|
21

For Asp.Net Core 2.x you basically need these 3 things in order to return an XML response:

Startup.cs:

services
    .AddMvcCore(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter())

CustomerController.cs:

using Microsoft.AspNetCore.Mvc;

namespace WebApplication
{
    [Route("api/[controller]")]
    public class CustomerController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            var customer = new CustomerDto {Id = 1, Name = "John", Age = 45};
            return Ok(customer);
        }
    }
}

CustomerDto.cs:

namespace WebApplication
{
    public class CustomerDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

And then upon adding the Accept "application/xml" header to the request an XML formatted result will be returned.

A very important note that I had to find out for myself is if your model does not have an implicit of explicit parameterless constructor then the response will be written as a json. Given the following example

namespace WebApplication
{
    public class CustomerDto
    {
        public CustomerDto(int id, string name, int age)
        {
            Id = id;
            Name = name;
            Age = age;
        }

         public int Id { get; }
         public string Name { get; }
         public int Age { get; }
    }
}

It would return json. To this model you should add

public CustomerDto()
{
}

And that would again return XML.

4 Comments

+1 for the parameterless constructor point, without that someone would spend hours scratching his head wondering what's going on !
Isn't this based on the Accept header that's provided.. I'm pretty sure that's how the API worked..
Regarding the parameterless constructor: this is also true when returning an anonymous object. When you do it will always return JSON!
Regarding the parameterless constructor, this applies to any nested objects as well. There must be parameterless constructors all the way down or it will return JSON.
7

The following solution worked for me nicely.

At Startup.cs

services.AddMvc()
       .AddXmlSerializerFormatters()
       .AddXmlDataContractSerializerFormatters();

At YourController.cs

    [HttpGet]
    [Route("Get")]
    [Produces("application/xml")] // If you don't like to send Content-Type header
    public IActionResult Get()
    {
        try
        {                
            var user = _userManager.FindByNameAsync('user').Result;
            if (user != null)
            {
                if (!_userManager.CheckPasswordAsync(user, 'password').Result)
                {
                    return Unauthorized();
                }
                else
                {
                    var result = _services.GetDataFromService(Convert.ToInt64(2), start_date, end_date);
                    return Ok(result);
                }
            }
            else
            {
                return Unauthorized();
            }
        }
        catch (Exception ex)
        {
            return Unauthorized();
        }
    }

Comments

6

For MVC 1.1 you need to add the Package Microsoft.AspNetCore.Mvc.Formatters.Xml and edit your Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; })
        .AddXmlSerializerFormatters()
        .AddXmlDataContractSeria‌​lizerFormatters();
}

Now you can set the Accept Header:

XML: application/xml

JSON: application/json

Comments

6

For asp.net core 2.x, you can configure OutputFormatter.

you can try following code pieces in startup.cs class ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
     services.AddMvc(action =>
     {
         action.ReturnHttpNotAcceptable = true;
         action.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
     });

     //...
}

For using XmlDataContractSerializerOutputFormatter references from Microsoft.AspNetCore.Mvc.Formatters package from nuget.

now it should work for xml and json

Comments

2

For .net core 3.x , you can use like below

services.AddControllers(options=> {
            options.OutputFormatters.RemoveType(typeof(SystemTextJsonOutputFormatter));
            options.InputFormatters.RemoveType(typeof(SystemTextJsonInputFormatter));
            options.ReturnHttpNotAcceptable = true;
        }).AddXmlSerializerFormatters();

Comments

0

For Core 2.x versions, the only thing that you need to do is to have the following code inside the ConfigureServie method of Startup.cs file.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
            .AddMvcOptions(o => o.OutputFormatters.Add(
              new XmlDataContractSerializerOutputFormatter()));
}

You need to reference the Microsoft.AspNetCore.Mvc.Formatters.

Comments

0

For Core 2.x versions, you have to do two things. First thing is you need to add following code inside the ConfigureServices method of Startup.cs file.

services.AddMvc()
.AddMvcOptions(o => o.OutputFormatters.Add(
    new XmlDataContractSerializerOutputFormatter())
);

And then add the Accept "application/xml" header to the request as below on Postman. Then XML formatted result will be returned.

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.