Closed mikekistler closed 3 months ago
So, I believe the behavior here is as expected, albeit confusing if you're not familiar with MVC's input formatters. When we discussed this offline, I shared my hunch that this might be related to the fact that an input formatter for application/octet-stream
isn't registered in the application. We tried to confirm this hunch by using another content-type that might apply (text/plain
) but that didn't appear to work either...
...and that's because there's no input formatter configured for the text/plain
content-type by default. The only input formatters MVC will configure by default are for application/json
.
By default, MVC's ApiExplorer layer will check the set of content-types provided via the Consumes
attributes against the registered input formatters here:
Anything that doesn't pass the vibe check doesn't actually end up populating the response metadata. This functionally checks out with the way the API handles incoming requests with the application/octet-stream type. If no formatter is registered, the request will be rejected with a 415.
POST /request-bodies/non-json-body HTTP/1.1
Content-Length: 0
Content-Type: application/octet-stream
Host: localhost:5159
User-Agent: HTTPie
HTTP/1.1 415 Unsupported Media Type
Connection: close
Content-Type: application/problem+json; charset=utf-8
Date: Wed, 31 Jul 2024 02:45:52 GMT
Server: Kestrel
Transfer-Encoding: chunked
{"type":"https://tools.ietf.org/html/rfc9110#section-15.5.16","title":"Unsupported Media Type","status":415,"traceId":"00-77d5052a0a43cbeda676098472cd420e-3493138586cecc94-00"}
You can resolve this by implementing an input formatter like in the stub below:
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSwaggerGen();
builder.Services.AddControllers(options => {
options.InputFormatters.Add(new StreamInputFormatter());
});
builder.Services.AddOpenApi(options => {
options.UseTransformer<InfoTransformer>();
options.UseTransformer((document, context, cancellationToken) =>
{
document.Servers = new List<OpenApiServer>
{
new OpenApiServer
{
Url = "http://localhost:5000",
Description = "Local development server"
}
};
return Task.CompletedTask;
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
public class StreamInputFormatter : IInputFormatter, IApiRequestFormatMetadataProvider
{
public bool CanRead(InputFormatterContext context) =>
context.HttpContext.Request.ContentType is { } contentType &&
contentType == "application/octet-stream";
public IReadOnlyList<string>? GetSupportedContentTypes(string contentType, Type objectType)
{
return ["application/octet-stream"];
}
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
=> InputFormatterResult.SuccessAsync(new byte[1] { 0xFF });
}
That gets the desired result as far as actual runtime behavior:
POST /request-bodies/non-json-body HTTP/1.1
Content-Length: 0
Content-Type: application/octet-stream
Host: localhost:5159
User-Agent: HTTPie
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json; charset=utf-8
Date: Wed, 31 Jul 2024 02:50:08 GMT
Server: Kestrel
Transfer-Encoding: chunked
"Good to go"
And the generated OpenAPI:
"/request-bodies/non-json-body": {
"post": {
"tags": [
"RequestBodies"
],
"requestBody": {
"description": "A non-Json request body",
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "byte"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
Is there an existing issue for this?
Describe the bug
In a controller-based app, the
Consumes
attribute/filter can be used to specify the supported request content types. But these content-types do not appear in therequestBody
field of the operation in the generated OpenAPI document.As an example, for the following endpoint:
the corresponding operation in the generated OpenAPI document is:
Note that the MIME type shown in the request body is "application/json" and not "application/octet-stream".
Expected Behavior
The content-type specified in the Consumes attribute is the one shown in the requestBody field of the corresponding operation in the generated OpenAPI.
Steps To Reproduce
I have a recreate in the bug-57090 branch of my aspnet-openapi-examples project:
https://github.com/mikekistler/aspnet-openapi-examples/tree/bug-57090
Exceptions (if any)
No response
.NET Version
9.0.100-rc.1.24380.1
Anything else?
No response