Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Text.Json.Schema;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Http.Json;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Infrastructure;
Expand Down Expand Up @@ -58,9 +59,11 @@ internal sealed class OpenApiSchemaService(
TransformSchemaNode = (context, schema) =>
{
var type = context.TypeInfo.Type;
// Fix up schemas generated for IFormFile, IFormFileCollection, Stream, PipeReader and FileContentResult
// Fix up schemas generated for IFormFile, IFormFileCollection, Stream, PipeReader,
// FileContentResult, FileStreamResult, FileContentHttpResult and FileStreamHttpResult
// that appear as properties within complex types.
if (type == typeof(IFormFile) || type == typeof(Stream) || type == typeof(PipeReader) || type == typeof(Mvc.FileContentResult))
if (type == typeof(IFormFile) || type == typeof(Stream) || type == typeof(PipeReader)
|| type == typeof(Mvc.FileContentResult) || type == typeof(Mvc.FileStreamResult) || type == typeof(FileContentHttpResult) || type == typeof(FileStreamHttpResult))
{
schema = new JsonObject
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public class Baz
[typeof(Stream), "Stream"],
[typeof(PipeReader), "PipeReader"],
[typeof(FileContentResult), "FileContentResult"],
[typeof(FileStreamResult), "FileStreamResult"],
[typeof(FileContentHttpResult), "FileContentHttpResult"],
[typeof(FileStreamHttpResult), "FileStreamHttpResult"],
[typeof(Results<Ok<TodoWithDueDate>, Ok<Todo>>), "ResultsOfOkOfTodoWithDueDateAndOkOfTodo"],
[typeof(Ok<Todo>), "OkOfTodo"],
[typeof(NotFound<TodoWithDueDate>), "NotFoundOfTodoWithDueDate"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;

public partial class OpenApiSchemaServiceTests : OpenApiDocumentServiceTestBase
Expand Down Expand Up @@ -1055,6 +1056,75 @@ await VerifyOpenApiDocument(builder, document =>
});
}

[Fact]
public async Task GetOpenApiResponse_HandlesFileStreamResultTypeResponse()
{
// Arrange
var builder = CreateBuilder();

// Act
builder.MapPost("/filestreamresult", () => { return new FileStreamResult(new MemoryStream(), MediaTypeNames.Application.Octet); })
.Produces<FileStreamResult>(contentType: MediaTypeNames.Application.Octet);

// Assert
await VerifyOpenApiDocument(builder, document =>
{
var operation = document.Paths["/filestreamresult"].Operations[HttpMethod.Post];
var responses = Assert.Single(operation.Responses);
var response = responses.Value;
Assert.True(response.Content.TryGetValue("application/octet-stream", out var mediaType));
var schema = mediaType.Schema;
Assert.Equal(JsonSchemaType.String, schema.Type);
Assert.Equal("binary", schema.Format);
});
}

[Fact]
public async Task GetOpenApiResponse_HandlesFileContentHttpResultTypeResponse()
{
// Arrange
var builder = CreateBuilder();

// Act
builder.MapPost("/filecontenthttpresult", () => { return TypedResults.File([], MediaTypeNames.Image.Png); })
.Produces<FileContentHttpResult>(contentType: MediaTypeNames.Image.Png);

// Assert
await VerifyOpenApiDocument(builder, document =>
{
var operation = document.Paths["/filecontenthttpresult"].Operations[HttpMethod.Post];
var responses = Assert.Single(operation.Responses);
var response = responses.Value;
Assert.True(response.Content.TryGetValue("image/png", out var mediaType));
var schema = mediaType.Schema;
Assert.Equal(JsonSchemaType.String, schema.Type);
Assert.Equal("binary", schema.Format);
});
}

[Fact]
public async Task GetOpenApiResponse_HandlesFileContentStreamResultTypeResponse()
{
// Arrange
var builder = CreateBuilder();

// Act
builder.MapPost("/filestreamhttpresult", () => { return TypedResults.File(new MemoryStream(), MediaTypeNames.Application.Pdf); })
.Produces<FileStreamHttpResult>(contentType: MediaTypeNames.Application.Pdf);

// Assert
await VerifyOpenApiDocument(builder, document =>
{
var operation = document.Paths["/filestreamhttpresult"].Operations[HttpMethod.Post];
var responses = Assert.Single(operation.Responses);
var response = responses.Value;
Assert.True(response.Content.TryGetValue("application/pdf", out var mediaType));
var schema = mediaType.Schema;
Assert.Equal(JsonSchemaType.String, schema.Type);
Assert.Equal("binary", schema.Format);
});
}

[ApiController]
[Produces("application/json")]
public class TestController
Expand Down
Loading