ASP.NET Core Pitfalls - Content Type Mismatch

Introduction

To get the new year started, another post on my ASP.NET Core Pitfalls series! This time, it's related to APIs, and how the [Consumes] attribute is interpreted.

The Problem

The Content-Type header and optional charset parameter are part of the web standard and used to tell the server handler what type of content the client will send. The charset part is optional, and the default is "ascii"; for example, if we wish to set it as UTF-8, we should sent:

Content-Type: application/json;charset=utf-8

Now, charset is optional, and does not really change what the content type is, just the character set of the text of the payload.

In ASP.NET Core, it can be used to route the request to different endpoints: for example, two action methods for the same action can consume different content types. There is an attribute, [Consumes], which can be used in ASP.NET Core MVC to restrict the content types that are accepted by a given action method.

[HttpGet("Get")]
[Consumes("application/json;charset=utf-8")]
public IActionResult GetWithCharset() { ... }

[HttpGet("Get")]
[Consumes("application/json")]
public IActionResult GetWithCharset() { ... }

Both actions will respond on the same /Get endpoint, but what will be called depends on the content type sent.

Now, [Consumes] requires the exact content-type specified, so, for example, if you have this on some MVC action method:

[Consumes("application/json;charset=utf-8")]
public IActionResult Get() { ... }

And send "application/json" as the content type, you will get an HTTP 404 Not Found error!

Someone already noticed this and raised a bug with Microsoft: https://github.com/dotnet/aspnetcore/issues/18952. This was, unfortunately, closed long time ago, but there is a solution (kind of).

Even though you cannot add multiple [Consumes] attributes, because the ConsumesAttribute class doesn't allow it, you can pass additional content types to accept on the constructor. The solution is to include all content-types as other content types to accept (order is irrelevant):

[Consumes("application/json;charset=utf-8", "application/json")]
public IActionResult Get() { ... }

Conclusion

This is just a heads up, fortunately, there's a way around it. Stay tuned for more!

Comments

Popular posts from this blog

C# Magical Syntax

OpenTelemetry with ASP.NET Core

.NET 10 Validation