Asp.Net Core swagger Help Pages for IFormFile
Solution 1
For you ASP.NET Core developers, there's an issue written up in the Swashbuckle.AspNetCore GitHub repo for this: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/193. It has some working code for an OperationFilter in the comments as well -- that one worked better for me than the other ones in this question.
Solution 2
I have the same issue and your solution helped me.
I just changed the OperationFilter because my IFormFile parameter was not a nested parameter but the main parameter of the action method.
public class AddFileUploadParams : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
return;
var formFileParams = context.ApiDescription.ActionDescriptor.Parameters
.Where(x => x.ParameterType.IsAssignableFrom(typeof(IFormFile)))
.Select(x => x.Name)
.ToList(); ;
var formFileSubParams = context.ApiDescription.ActionDescriptor.Parameters
.SelectMany(x => x.ParameterType.GetProperties())
.Where(x => x.PropertyType.IsAssignableFrom(typeof(IFormFile)))
.Select(x => x.Name)
.ToList();
var allFileParamNames = formFileParams.Union(formFileSubParams);
if (!allFileParamNames.Any())
return;
var paramsToRemove = new List<IParameter>();
foreach (var param in operation.Parameters)
{
paramsToRemove.AddRange(from fileParamName in allFileParamNames where param.Name.StartsWith(fileParamName + ".") select param);
}
paramsToRemove.ForEach(x => operation.Parameters.Remove(x));
foreach (var paramName in allFileParamNames)
{
var fileParam = new NonBodyParameter
{
Type = "file",
Name = paramName,
In = "formData"
};
operation.Parameters.Add(fileParam);
}
foreach (IParameter param in operation.Parameters)
{
param.In = "formData";
}
operation.Consumes = new List<string>() { "multipart/form-data" };
}
}
I suppose you use SwashBuckle to generate the swagger. It would be nice if swashBuckle would handle this. Maybe i'll contribute if i have time left over.
YuriyP
Asp.Net MVC developer at Infoservice, Khmelnitsky, Ukraine
Updated on July 26, 2022Comments
-
YuriyP almost 2 years
I am trying to setup swagger for testing models which have IFormFile properties. For example I have next api method
[HttpPost] public ApiResult<UserModel> SaveTestFileData([FromForm]TestPostFileArgs args) { var result = new UserModel() { Id = 1, Name = $"SaveTestFileData {args.UserId} company: {args.CompanyId}, file length: {args.CompanyFile.Length}" }; return ApiResult.Success(result); }
And my parameter model
public class TestPostFileArgs { public int UserId { get; set; } public int? CompanyId { get; set; } public IFormFile CompanyFile { get; set; } }
By default swagger generate help page which does not allow to test it To solve this problem I wrote next OperationFilter
public class FormFileOperationFilter: IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { if (operation.Parameters == null) return; var fileParamNames = context.ApiDescription.ActionDescriptor.Parameters .SelectMany(x => x.ParameterType.GetProperties()) .Where(x => x.PropertyType.IsAssignableFrom(typeof (IFormFile))) .Select(x => x.Name) .ToList(); if (!fileParamNames.Any()) return; var paramsToRemove = new List<IParameter>(); foreach (var param in operation.Parameters) { paramsToRemove.AddRange(from fileParamName in fileParamNames where param.Name.StartsWith(fileParamName + ".") select param); } paramsToRemove.ForEach(x => operation.Parameters.Remove(x)); foreach (var paramName in fileParamNames) { var fileParam = new NonBodyParameter { Type = "file", Name = paramName, In = "formData" }; operation.Parameters.Add(fileParam); } foreach (IParameter param in operation.Parameters) { param.In = "formData"; } operation.Consumes = new List<string>() { "multipart/form-data" }; } }
And after this everething works as I expect from swagger.
For now this solution works for me, but it feels not right. Maybe I am missing some simple solution for this. Also this approach does not handle List or complex object properties with IFormFile or maybe something else.
-
A X over 3 yearsThis doesn't compile