I have implemented endpoint with this signature
[HttpPost("Test")]
public IActionResult MyTest([Required] IFormFile pdf, [Required] IFormFile image)
{
// some stuff...
return Ok();
}
this generates following entry in swagger.json (the relevant part)
"content": {
"multipart/form-data": {
"schema": {
"required": [
"image",
"pdf"
],
"type": "object",
"properties": {
"pdf": {
"type": "string",
"format": "binary"
},
"image": {
"type": "string",
"format": "binary"
}
}
},
"encoding": {
"pdf": {
"style": "form"
},
"image": {
"style": "form"
}
}
}
}
but, I also need specify encoding, like in the specs (v3). So for my task, that JSON should look like this, I think...
"encoding": {
"pdf": {
"style": "form",
"contentType": "application/pdf"
},
"image": {
"style": "form",
"contentType": "image/png, image/jpeg"
}
}
But how can I do that from code? I thought about SwaggerParameter attribute, but it contains only description and required flag...
I'm using Swashbuckle.AspNetCore NuGeT package (version 5.0.0-rc2) on .NET Core 2.2.
If you look at this line, you'll see that encoding is created with only Style
property, while ContentType
is not set. What you can do is set this manually by creating custom Attribute
where you'd define your content type:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,AllowMultiple = false)]
public class OpenApiEncodingContentTypeAttribute : Attribute
{
public OpenApiEncodingContentTypeAttribute(string contentType)
{
ContentType = contentType;
}
public string ContentType { get; }
}
and then use that Attribute
within IOperationFilter
public class FormContentTypeSchemaOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var contentTypeByParameterName = context.MethodInfo.GetParameters()
.Where(p => p.IsDefined(typeof(OpenApiEncodingContentTypeAttribute), true))
.ToDictionary(p => p.Name, s => s.GetCustomAttribute<OpenApiEncodingContentTypeAttribute>().ContentType);
if (contentTypeByParameterName.Any())
{
foreach (var requestContent in operation.RequestBody.Content)
{
var encodings = requestContent.Value.Encoding;
foreach (var encoding in encodings)
{
if (contentTypeByParameterName.TryGetValue(encoding.Key, out string value))
{
encoding.Value.ContentType = value;
}
}
}
}
}
}
Then just decorate your parameters with this Attribute
[HttpPost("Test")]
public IActionResult MyTest([Required] [OpenApiEncodingContentType("application/pdf")] IFormFile pdf, [Required] [OpenApiEncodingContentType("image/png, image/jpeg")] IFormFile image)
{
// some stuff...
return Ok();
}
Also don't forget to define your IOperationFilter
in AddSwaggerGen
services.AddSwaggerGen(opts =>
{
// all other stuff
opts.OperationFilter<FormContentTypeSchemaOperationFilter>();
})
This is what you get
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"required": [
"image",
"pdf"
],
"type": "object",
"properties": {
"pdf": {
"type": "string",
"format": "binary"
},
"image": {
"type": "string",
"format": "binary"
}
}
},
"encoding": {
"pdf": {
"contentType": "application/pdf",
"style": "form"
},
"image": {
"contentType": "image/png, image/jpeg",
"style": "form"
}
}
}
}
}
You can probably improve IOperationFilter
with additional checks/null-checks and other stuff that suits your needs, because this is just a basic implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With