Skip to content

Commit cb2f839

Browse files
committed
Support new HTTP result types in OpenAPI schema generation
Added support for `FileStreamResult`, `FileContentHttpResult`, and `FileStreamHttpResult` in `OpenApiSchemaService`. These types are now represented as binary string schemas in OpenAPI documentation. Updated `JsonTypeInfoExtensionsTests` to include test cases for the new types, ensuring proper handling and naming in the schema. Added new test cases in `OpenApiSchemaServiceTests` to verify OpenAPI response handling for the new HTTP result types, validating schema generation with appropriate content types. These changes improve compatibility with new ASP.NET Core features and enhance the accuracy of API documentation.
1 parent 0d10296 commit cb2f839

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Text.Json.Schema;
1313
using System.Text.Json.Serialization.Metadata;
1414
using Microsoft.AspNetCore.Http;
15+
using Microsoft.AspNetCore.Http.HttpResults;
1516
using Microsoft.AspNetCore.Http.Json;
1617
using Microsoft.AspNetCore.Mvc.ApiExplorer;
1718
using Microsoft.AspNetCore.Mvc.Infrastructure;
@@ -58,9 +59,11 @@ internal sealed class OpenApiSchemaService(
5859
TransformSchemaNode = (context, schema) =>
5960
{
6061
var type = context.TypeInfo.Type;
61-
// Fix up schemas generated for IFormFile, IFormFileCollection, Stream, PipeReader and FileContentResult
62+
// Fix up schemas generated for IFormFile, IFormFileCollection, Stream, PipeReader,
63+
// FileContentResult, FileStreamResult, FileContentHttpResult and FileContentHttpResult
6264
// that appear as properties within complex types.
63-
if (type == typeof(IFormFile) || type == typeof(Stream) || type == typeof(PipeReader) || type == typeof(Mvc.FileContentResult))
65+
if (type == typeof(IFormFile) || type == typeof(Stream) || type == typeof(PipeReader)
66+
|| type == typeof(Mvc.FileContentResult) || type == typeof(Mvc.FileStreamResult) || type == typeof(FileContentHttpResult) || type == typeof(FileStreamHttpResult))
6467
{
6568
schema = new JsonObject
6669
{

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Extensions/JsonTypeInfoExtensionsTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public class Baz
6464
[typeof(Stream), "Stream"],
6565
[typeof(PipeReader), "PipeReader"],
6666
[typeof(FileContentResult), "FileContentResult"],
67+
[typeof(FileStreamResult), "FileStreamResult"],
68+
[typeof(FileContentHttpResult), "FileContentHttpResult"],
69+
[typeof(FileStreamHttpResult), "FileStreamHttpResult"],
6770
[typeof(Results<Ok<TodoWithDueDate>, Ok<Todo>>), "ResultsOfOkOfTodoWithDueDateAndOkOfTodo"],
6871
[typeof(Ok<Todo>), "OkOfTodo"],
6972
[typeof(NotFound<TodoWithDueDate>), "NotFoundOfTodoWithDueDate"],

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ResponseSchemas.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Text.Json.Nodes;
88
using Microsoft.AspNetCore.Builder;
99
using Microsoft.AspNetCore.Http;
10+
using Microsoft.AspNetCore.Http.HttpResults;
1011
using Microsoft.AspNetCore.Mvc;
1112

1213
public partial class OpenApiSchemaServiceTests : OpenApiDocumentServiceTestBase
@@ -1055,6 +1056,75 @@ await VerifyOpenApiDocument(builder, document =>
10551056
});
10561057
}
10571058

1059+
[Fact]
1060+
public async Task GetOpenApiResponse_HandlesFileStreamResultTypeResponse()
1061+
{
1062+
// Arrange
1063+
var builder = CreateBuilder();
1064+
1065+
// Act
1066+
builder.MapPost("/filestreamresult", () => { return new FileStreamResult(new MemoryStream(), MediaTypeNames.Application.Octet); })
1067+
.Produces<FileStreamResult>(contentType: MediaTypeNames.Application.Octet);
1068+
1069+
// Assert
1070+
await VerifyOpenApiDocument(builder, document =>
1071+
{
1072+
var operation = document.Paths["/filestreamresult"].Operations[HttpMethod.Post];
1073+
var responses = Assert.Single(operation.Responses);
1074+
var response = responses.Value;
1075+
Assert.True(response.Content.TryGetValue("application/octet-stream", out var mediaType));
1076+
var schema = mediaType.Schema;
1077+
Assert.Equal(JsonSchemaType.String, schema.Type);
1078+
Assert.Equal("binary", schema.Format);
1079+
});
1080+
}
1081+
1082+
[Fact]
1083+
public async Task GetOpenApiResponse_HandlesFileContentHttpResultTypeResponse()
1084+
{
1085+
// Arrange
1086+
var builder = CreateBuilder();
1087+
1088+
// Act
1089+
builder.MapPost("/filecontenthttpresult", () => { return TypedResults.File([], MediaTypeNames.Image.Png); })
1090+
.Produces<FileContentHttpResult>(contentType: MediaTypeNames.Image.Png);
1091+
1092+
// Assert
1093+
await VerifyOpenApiDocument(builder, document =>
1094+
{
1095+
var operation = document.Paths["/filecontenthttpresult"].Operations[HttpMethod.Post];
1096+
var responses = Assert.Single(operation.Responses);
1097+
var response = responses.Value;
1098+
Assert.True(response.Content.TryGetValue("image/png", out var mediaType));
1099+
var schema = mediaType.Schema;
1100+
Assert.Equal(JsonSchemaType.String, schema.Type);
1101+
Assert.Equal("binary", schema.Format);
1102+
});
1103+
}
1104+
1105+
[Fact]
1106+
public async Task GetOpenApiResponse_HandlesFileContentStreamResultTypeResponse()
1107+
{
1108+
// Arrange
1109+
var builder = CreateBuilder();
1110+
1111+
// Act
1112+
builder.MapPost("/filestreamhttpresult", () => { return TypedResults.File(new MemoryStream(), MediaTypeNames.Application.Pdf); })
1113+
.Produces<FileStreamHttpResult>(contentType: MediaTypeNames.Application.Pdf);
1114+
1115+
// Assert
1116+
await VerifyOpenApiDocument(builder, document =>
1117+
{
1118+
var operation = document.Paths["/filestreamhttpresult"].Operations[HttpMethod.Post];
1119+
var responses = Assert.Single(operation.Responses);
1120+
var response = responses.Value;
1121+
Assert.True(response.Content.TryGetValue("application/pdf", out var mediaType));
1122+
var schema = mediaType.Schema;
1123+
Assert.Equal(JsonSchemaType.String, schema.Type);
1124+
Assert.Equal("binary", schema.Format);
1125+
});
1126+
}
1127+
10581128
[ApiController]
10591129
[Produces("application/json")]
10601130
public class TestController

0 commit comments

Comments
 (0)