dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.44k stars 10.02k forks source link

Issue with Wildcard Media Types #18891

Open sudixi opened 4 years ago

sudixi commented 4 years ago

We have an ASP.NET core web API help pages with Swagger (swashbuckle). If there is any error , then we want to send the error with the content-type set to “application/*+json”.

Something like this appears to works:

namespace TodoApi.Controllers
{
    #region snippet_TodoController
    [Produces("application/json", "application/problem+json" , "text/plain")]
    [Route("api/[controller]")]
    public class TodoController : ControllerBase
    {
     ================ Trimmed ================        

       [HttpPost] 
   [ProducesResponseType(201)]
   [ProducesResponseType(400)]
        public IActionResult Create([FromBody] TodoItem item)
        {
            if (item == null)
            {
                ContentResult a = new ContentResult();
                a.ContentType = "application/problem+json";
                a.StatusCode = 400;
                return a;
            }

            _context.TodoItems.Add(item);
            _context.SaveChanges();

            return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
        }

.. but we expect the ProblemDetailsClientErrorFactory to handle this automatically, which it appears to do, but it does not stick when the Produces Attribute is present:

image

If the Produces Attribute is not used, the correct content type is returned, but the metadata is incomplete (application/problem+json is missing).

We feel the issue is here:

The JsonOutputFormatter defines three media types (text/plan, application/json and application/+json). The application/+json is never returned through the API Explorer because of the wildcard handling. The API Explorer requests all supported content types from the the OutputFormatter (GetSupportedContentTypes) by passing the null value (from GetApiResponseTypes). The issue is that wildcard media types are handled differently and are never returned when null is passed.

For more details, see:

https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonOutputFormatter.cs [https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.ApiExplorer/src/ApiResponseTypeProvider.cs (GetApiResponseTypes)](https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.ApiExplorer/src/ApiResponseTypeProvider.cs (GetApiResponseTypes)) [https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.Core/src/Formatters/OutputFormatter.cs (GetSupportedContentTypes)](https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.Core/src/Formatters/OutputFormatter.cs (GetSupportedContentTypes))

The JsonOutputFormatter adds application/*+json

image

The ApiResponseTypeProvider adds a null content type

image

… and then requests the SupportedContentTypes with null:

image

This is where we believe the issue is (OutputFormatter). If the media type is not a wildcard (ex: text/plain) and you pass null, it will be added (else branch). If it’s a wildcard though (like application/*+json), it won’t be added (if branch).

image

Is this supposed to work like this..?

mkArtakMSFT commented 4 years ago

Thanks for contacting us. We'll look into this and get back to you as soon as we have more details about what's going on here. Please don't expect an immediate outcome as we prioritize this with many other work items.

SurajDixit commented 4 years ago

Thanks for the update!

Looking forward to hear from you!

jeremysimmons commented 4 years ago

Looks like this is also a problem in https://github.com/dotnet/aspnetcore/issues/19510