Search code examples
c#asp.net-core.net-6.0netcoreapp3.1

Content-Type negation doesn't work upgrading from netcoreapp3.1 to net6 ASP.NET Core


I'm (trying) to upgrade ASP.NET Core application from .NET Core App 3.1 to .NET 6 but one test fails that deserialize a Problem result. Reason for failing is that in .NET 6 the content type is application/problem+json whilst in .NET Core App 3.1 application/xml.

Have searched for any notes regarding this in migration document but can't find anything.

A repro is available in my GitHub and the controller is very simple

using System.Net.Mime;
using Microsoft.AspNetCore.Mvc;

namespace ProblemDetailsXMLSerialization
{
    [ApiController]
    [Route("[controller]")]
    public class XmlController : ControllerBase
    {
        [HttpPost]
        [Produces(MediaTypeNames.Application.Xml)]
        [Consumes(MediaTypeNames.Application.Xml)]
        public IActionResult Xml()
        {
            return Problem();
        }
    }
}

// Test file
using Microsoft.AspNetCore.Mvc.Testing;
using ProblemDetailsXMLSerialization;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace TestProject1
{
    public class UnitTest1
    {
        [Fact]
        public async Task Test1()
        {
            // Arrange
            var application = new WebApplicationFactory<Startup>();
            var client = application.CreateClient();

            // Act
            const string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>";
            var content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
            var response = await client.PostAsync("xml", content);

            // Assert
            Assert.Equal(MediaTypeNames.Application.Xml, response.Content.Headers.ContentType.MediaType);
            var responseString = await response.Content.ReadAsStringAsync();
        }
    }
}

Thanks


Solution

  • To get an XML response - matching your assert statement - you'll need to add an Accept HTTP header with value application/xml.

    From the documentation:

    Content negotiation occurs when the client specifies an Accept header. The default format used by ASP.NET Core is JSON.


    var content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
    client.DefaultRequestHeaders.Add(
        "Accept", "application/xml"
        );
    var response = await client.PostAsync("xml", content);
    

    There are built-in strings for both Accept and application/xml.

    client.DefaultRequestHeaders.Add(
        Microsoft.Net.Http.Headers.HeaderNames.Accept,  
        System.Net.Mime.MediaTypeNames.Application.Xml
        );
    

    Setting that header to the DefaultRequestHeaders makes it being sent with every request made by that HttpClient instance.

    In case you only want/need it for a single request, then use a HttpRequestMessage instance.

    using (var request = new HttpRequestMessage(HttpMethod.Post, "xml"))
    {
        request.Headers.Add("accept", "application/xml");
        request.Content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
        var response = await client.SendAsync(request);
    
        var responseString = await response.Content.ReadAsStringAsync();
    }
    

    In either case, the responseString variable will contain an xml payload similar to below one.

    <problem xmlns="urn:ietf:rfc:7807">
        <status>500</status>
        <title>An error occurred while processing your request.</title>
        <type>https://tools.ietf.org/html/rfc7231#section-6.6.1</type>
        <traceId>00-26c29d0830bd0a5a417e9bab9746bd23-3cfbc9589ffd8182-00</traceId>
    </problem>