Add support for multipart/data uploads in swagger
This commit is contained in:
@@ -5,6 +5,7 @@ using FrameProcessor.Middleware;
|
|||||||
using FrameProcessor.Mqtt;
|
using FrameProcessor.Mqtt;
|
||||||
using FrameProcessor.Storage;
|
using FrameProcessor.Storage;
|
||||||
using FrameProcessor.UrlFetch;
|
using FrameProcessor.UrlFetch;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.OpenApi;
|
using Microsoft.OpenApi;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
@@ -50,6 +51,68 @@ builder.Services.AddOpenApi(options =>
|
|||||||
];
|
];
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Microsoft.AspNetCore.OpenApi (10.0) does not emit a multipart/form-data
|
||||||
|
// request body for [FromForm] IFormFile parameters on MVC controllers, so
|
||||||
|
// Swagger UI renders no upload widget. Synthesize one here for any operation
|
||||||
|
// whose action takes form-bound parameters.
|
||||||
|
options.AddOperationTransformer((operation, context, _) =>
|
||||||
|
{
|
||||||
|
var formParams = context.Description.ParameterDescriptions
|
||||||
|
.Where(p => p.Source == BindingSource.FormFile || p.Source == BindingSource.Form)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (formParams.Count == 0)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = new Dictionary<string, IOpenApiSchema>();
|
||||||
|
var required = new HashSet<string>();
|
||||||
|
|
||||||
|
foreach (var p in formParams)
|
||||||
|
{
|
||||||
|
var isFile = p.Source == BindingSource.FormFile
|
||||||
|
|| typeof(IFormFile).IsAssignableFrom(p.ModelMetadata?.ModelType);
|
||||||
|
|
||||||
|
properties[p.Name] = new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = JsonSchemaType.String,
|
||||||
|
Format = isFile ? "binary" : null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (p.IsRequired)
|
||||||
|
{
|
||||||
|
required.Add(p.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operation.RequestBody = new OpenApiRequestBody
|
||||||
|
{
|
||||||
|
Required = true,
|
||||||
|
Content = new Dictionary<string, OpenApiMediaType>
|
||||||
|
{
|
||||||
|
["multipart/form-data"] = new OpenApiMediaType
|
||||||
|
{
|
||||||
|
Schema = new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = JsonSchemaType.Object,
|
||||||
|
Properties = properties,
|
||||||
|
Required = required,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (operation.Parameters is { Count: > 0 })
|
||||||
|
{
|
||||||
|
var formNames = formParams.Select(p => p.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
var filtered = operation.Parameters.Where(p => p.Name is null || !formNames.Contains(p.Name)).ToList();
|
||||||
|
operation.Parameters = filtered.Count > 0 ? filtered : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddOptions<MqttOptions>()
|
builder.Services.AddOptions<MqttOptions>()
|
||||||
|
|||||||
Reference in New Issue
Block a user