我有一个控制器,该控制器请求包含IFormFile作为其属性之一的模型。对于请求描述,Swagger UI(我正在使用Swashbuckle和.NET Core的OpenApi 3.0)将文件属性的类型作为类型对象列出。有什么方法可以使Swagger UI表示确切的类型,它是JSON表示形式来帮助客户端吗?
请求模型的控制器如下所示。
[HttpPost]
[Consumes("multipart/form-data")
public async Task<IActionResult> CreateSomethingAndUploadFile ([FromForm]RequestModel model)
{
// do something
}
模型定义如下:
public class AssetCreationModel
{
[Required}
public string Filename { get; set; }
[Required]
public IFormFile File { get; set; }
}
答案 0 :(得分:1)
以下github issue/thread已解决了此问题。
此改进已合并到Swashbuckle.AspNetCore
母版中(根据2018年10月30日),但我不希望很快将其作为软件包提供。
如果仅将IFormFile作为参数,则有简单的解决方案。
public async Task UploadFile(IFormFile filePayload){}
为简单起见,您可以查看以下answer。
对于诸如集装箱箱这样的复杂箱,您可以查看以下answer。
internal class FormFileOperationFilter : IOperationFilter
{
private struct ContainerParameterData
{
public readonly ParameterDescriptor Parameter;
public readonly PropertyInfo Property;
public string FullName => $"{Parameter.Name}.{Property.Name}";
public string Name => Property.Name;
public ContainerParameterData(ParameterDescriptor parameter, PropertyInfo property)
{
Parameter = parameter;
Property = property;
}
}
private static readonly ImmutableArray<string> iFormFilePropertyNames =
typeof(IFormFile).GetTypeInfo().DeclaredProperties.Select(p => p.Name).ToImmutableArray();
public void Apply(Operation operation, OperationFilterContext context)
{
var parameters = operation.Parameters;
if (parameters == null)
return;
var @params = context.ApiDescription.ActionDescriptor.Parameters;
if (parameters.Count == @params.Count)
return;
var formFileParams =
(from parameter in @params
where parameter.ParameterType.IsAssignableFrom(typeof(IFormFile))
select parameter).ToArray();
var iFormFileType = typeof(IFormFile).GetTypeInfo();
var containerParams =
@params.Select(p => new KeyValuePair<ParameterDescriptor, PropertyInfo[]>(
p, p.ParameterType.GetProperties()))
.Where(pp => pp.Value.Any(p => iFormFileType.IsAssignableFrom(p.PropertyType)))
.SelectMany(p => p.Value.Select(pp => new ContainerParameterData(p.Key, pp)))
.ToImmutableArray();
if (!(formFileParams.Any() || containerParams.Any()))
return;
var consumes = operation.Consumes;
consumes.Clear();
consumes.Add("application/form-data");
if (!containerParams.Any())
{
var nonIFormFileProperties =
parameters.Where(p =>
!(iFormFilePropertyNames.Contains(p.Name)
&& string.Compare(p.In, "formData", StringComparison.OrdinalIgnoreCase) == 0))
.ToImmutableArray();
parameters.Clear();
foreach (var parameter in nonIFormFileProperties) parameters.Add(parameter);
foreach (var parameter in formFileParams)
{
parameters.Add(new NonBodyParameter
{
Name = parameter.Name,
//Required = , // TODO: find a way to determine
Type = "file"
});
}
}
else
{
var paramsToRemove = new List<IParameter>();
foreach (var parameter in containerParams)
{
var parameterFilter = parameter.Property.Name + ".";
paramsToRemove.AddRange(from p in parameters
where p.Name.StartsWith(parameterFilter)
select p);
}
paramsToRemove.ForEach(x => parameters.Remove(x));
foreach (var parameter in containerParams)
{
if (iFormFileType.IsAssignableFrom(parameter.Property.PropertyType))
{
var originalParameter = parameters.FirstOrDefault(param => param.Name == parameter.Name);
parameters.Remove(originalParameter);
parameters.Add(new NonBodyParameter
{
Name = parameter.Name,
Required = originalParameter.Required,
Type = "file",
In = "formData"
});
}
}
}
}
}
您需要研究如何添加一些适合您情况的OperationFilter
。
答案 1 :(得分:0)
我们今天一直在探索这个问题。如果将以下内容添加到启动中,它将IFormFile转换为正确的类型
services.AddSwaggerGen(c => {
c.SchemaRegistryOptions.CustomTypeMappings.Add(typeof(IFormFile), () => new Schema() { Type = "file", Format = "binary"});
});
另请参阅以下有关.net core中文件上传的文章 https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1