Search code examples
schemaswashbuckle.aspnetcore

How to define 'File' Schema Type in Swashbuckle.AspNetCore


After updating Swashbuckle.AspNetCore from v4.0.1 to v.6.5.0, the following code can't be compiled anymore:

public class FileSchemaType : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        // TODO Replace this workaround (https://github.com/domaindrivendev/Swashbuckle/issues/1144) with a proper solution using e. g. attributes
        if (operation.OperationId == "ExportToExcel" || operation.OperationId == "ExportToPdf" ||
            operation.OperationId == "GetReport" || operation.OperationId == "DownloadFile")
        {
            operation.Responses["200"].Schema = new Schema {Type = "file"};
        }
    }
}

I had to rewrite the mentioned code to this:

public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
    // TODO Replace this workaround (https://github.com/domaindrivendev/Swashbuckle/issues/1144) with a proper solution using e. g. attributes
    if (operation.OperationId == "ExportToExcel" || operation.OperationId == "ExportToPdf" ||
        operation.OperationId == "GetReport" || operation.OperationId == "DownloadFile")
    {
        operation.Responses["200"].Schema = new Schema { Type = "file" };
    }
}

However, the property Schema doesn't exist anymore on operation.Responses["200"]

According to the release notes in v5.0.0-rc3 a number of significant changes, including a transition to Swagger/OpenAPI v3, were made in Swashbuckle.AspNetCore.


Solution

  • Using [Produces(typeof(HttpResponseMessage))] and returning a File instance...

    [Produces(typeof(HttpResponseMessage))]
    public async Task<IActionResult> ExportToExcel(string listName, string language, [FromBody] List<int> personIds,
        DateTime startDate, DateTime endDate, List<int> notSelectedTimeTypeIds
    )
    {
        var stream = await AbsencePlanningProvider.Instance.ExportToExcel(User.GetSub(), language, listName, personIds,
            startDate, endDate, notSelectedTimeTypeIds);
        stream.Position = 0;
        return File(stream, "application/octet-stream");
    }
    

    ...together with this operation filter solved the problem:

    public class FileSchemaType : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            // The listed operations must have the attribute [Produces(typeof(HttpResponseMessage))]
            // in addition to this operation filter
            if (operation.OperationId == "ExportToExcel" || operation.OperationId == "ExportToPdf" ||
                operation.OperationId == "GetReport" || operation.OperationId == "DownloadFile")
            {
                foreach (var item in operation.Responses["200"].Content)
                    item.Value.Schema = new OpenApiSchema { Type = "file" };
            }
        }
    }