我正在尝试设置swagger来测试具有IFormFile属性的模型。 例如,我有下一个api方法
[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);
}
我的参数模型
public class TestPostFileArgs
{
public int UserId { get; set; }
public int? CompanyId { get; set; }
public IFormFile CompanyFile { get; set; }
}
默认情况下,swagger会生成帮助页面,该页面不允许对其进行测试 为了解决这个问题,我写了下一个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" };
}
}
目前这个解决方案对我有用,但感觉不对。也许我错过了一些简单的解决方案。此方法也不使用IFormFile处理List或复杂对象属性,也可能不处理其他内容。
答案 0 :(得分:3)
对于ASP.NET Core开发人员,Swashbuckle.AspNetCore GitHub存储库中存在一个问题:https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/193。它在评论中也有一些适用于OperationFilter的工作代码 - 对于我来说,这个代码比这个问题中的其他代码更好。
答案 1 :(得分:2)
我有同样的问题,你的解决方案帮助了我。
我刚刚更改了OperationFilter,因为我的IFormFile参数不是嵌套参数,而是action方法的主要参数。
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" };
}
}
我想你使用SwashBuckle来生成招摇。 如果swashBuckle会处理这个问题会很好。如果我还有时间,也许我会做出贡献。
答案 2 :(得分:0)
使用
[Route("picture/pics/upload/")]
途中和
UploadPicture(IFormFile file)
在方法中 完整的代码是
[Route("picture/{Id:int:min(1)}/{sequence:int:min(1)}")]
[SwaggerResponse((int)HttpStatusCode.NotFound)]
[SwaggerResponse((int)HttpStatusCode.BadRequest)]
[SwaggerResponse((int)HttpStatusCode.InternalServerError)]
[SwaggerResponse((int)HttpStatusCode.OK, "The picture uploaded")]
[SwaggerOperation(
Summary = "upload a picture for new picture",
Description = "This action upload a picture for new picture",
OperationId = "UploadPictureAsync",
Tags = new[] { "Pictures:Post" }
)]
public async Task<ActionResult> UploadPictureAsync(int storeId, byte
sequence, IFormFile file )
{
...
}