Built-in OpenAPI generator emits 3.0-era `format: binary` for binary/file types in 3.1/3.2 documents
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Summary
`Microsoft.AspNetCore.OpenApi` now defaults `OpenApiOptions.OpenApiVersion` to `OpenApi3_2`, but the generator describes binary/file types using the OpenAPI **3.0-era** idiom `type: string, format: binary` — including when it produces 3.1 and 3.2 documents, where that representation is no longer part of the specification.
The same 3.0 shape is emitted verbatim regardless of the target document version (verified with the repro below on `11.0.100-preview.6`).
### Repro
`BinaryFormatRepro.csproj`:
```xml
net11.0
enable
enable
```
`Program.cs`:
```csharp
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.OpenApi;
var builder = WebApplication.CreateBuilder(args);
// Three documents that differ ONLY by target spec version.
builder.Services.AddOpenApi("v3_0", o => o.OpenApiVersion = OpenApiSpecVersion.OpenApi3_0);
builder.Services.AddOpenApi("v3_1", o => o.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1);
builder.Services.AddOpenApi("v3_2", o => o.OpenApiVersion = OpenApiSpecVersion.OpenApi3_2); // current default
var app = builder.Build();
app.MapOpenApi("/openapi/{documentName}.json");
// Binary response (file download)
app.MapGet("/download", () => Results.File(new byte[] { 1, 2, 3 }, "application/octet-stream"))
.Produces(StatusCodes.Status200OK, "application/octet-stream");
// Binary request (file upload)
app.MapPost("/upload", (IFormFile file) => Results.Ok());
app.Run();
```
Run it, then fetch the three documents:
```
curl http://localhost:5199/openapi/v3_0.json
curl http://localhost:5199/openapi/v3_1.json
curl http://localhost:5199/openapi/v3_2.json
```
### Actual behavior
The documents correctly declare different versions (`"openapi": "3.0.4"`, `"3.1.2"`, `"3.2.0"`), but the binary schema is **identical** in all three:
```jsonc
// components.schemas in v3_0.json, v3_1.json AND v3_2.json — byte-for-byte identical:
"FileContentHttpResult": { "type": "string", "format": "binary" },
"IFormFile": { "type": "string", "format": "binary" }
```
### Expected behavior
When generating a 3.1 or 3.2 document, binary data should use the JSON-Schema-2020-12–aligned representation rather than `format: binary`:
- Raw bytes: describe via the media type / `contentMediaType` (the schema can be omitted when the media type already conveys binary).
- Base64-in-JSON: `contentEncoding: base64` (this is the correct target for `byte[]`, and is distinct from raw-binary).
### Specification references
- OpenAPI 3.0 — `format: binary` describes file/binary content, `format: byte` is base64. See "String Formats" in the OpenAPI 3.0 Data Types guide: https://swagger.io/docs/specification/v3_0/data-models/data-types/
- OpenAPI 3.1.1 — §4.4.2 **Working with Binary Data**: https://spec.openapis.org/oas/v3.1.1.html#working-with-binary-data
- OpenAPI 3.1.1 — §4.4.2.1 **Migrating binary descriptions from OAS 3.0** (explicitly describes replacing `format: binary` / `format: byte` with `contentMediaType` / `contentEncoding`): https://spec.openapis.org/oas/v3.1.1.html#migrating-binary-descriptions-from-oas-3-0
Note: `format: binary` is not *invalid* under 3.1/3.2 (`format` is an open annotation), but it is the deprecated 3.0 idiom and not the representation the spec prescribes, so tooling that follows 3.1+ may not interpret it as binary.
### Scope
Affects all special-cased binary types in `src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs`:
- `IFormFile`, `IFormFileCollection`
- `Stream`, `PipeReader`
- `FileContentResult`, `FileStreamResult`
- `FileContentHttpResult`, `FileStreamHttpResult`
### Notes
- The earlier bug where `FileContentResult`/`FileContentHttpResult` mapped to an *object* `$ref` (#63172, #64561) is fixed — these types now produce a binary schema; this issue is specifically about that schema using the legacy 3.0 shape under 3.1/3.2.
- Related: #67145 (proposed `IBinaryContent` marker) would need this same version-aware mapping, so the two are worth designing together.
### .NET Version
11.0.100-preview.6.26315.102 (main)
Contributor guide
Assessment
This issue has not been assessed yet.