为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Swashbuckle Swagger 上传文件

使用 Swashbuckle Swagger 上传文件

C#
繁星coding 2021-11-14 15:50:47
我有一个带有 Swagger 3.0 的 ASP.NET Core 2 应用程序,我想通过从 Swagger UI 上传文件来测试 POST 操作。文件上传控制器:[ApiController]public class FileUploadController : ApiControllerBase{    private readonly IFileUploader _fileUploader;    public FileUploadController(IFileUploader fileUploader, ILogger<FileUploadController> logger) : base(logger)    {        _fileUploader = fileUploader;    }    [HttpPost]    [Route(nameof(UploadFile))]    public FileUploadResult UploadFile(IFormFile uploadedFile)    {        return _FileUploader.UploadFile(Request.Form.Files[0]);    }}阅读 Swagger 文档和其他主题,我发现我需要自定义 IOperationFilter,所以这就是我想出的:public class FileUploadOperationFilter : IOperationFilter{    public void Apply(Operation operation, OperationFilterContext context)    {        if (operation.OperationId.ToLower() == "apifileuploaduploadfilepost")        {            operation.Parameters.Add(new NonBodyParameter()            {                Name = "file",                In = "formData",                Description = "Upload File",                Required = true,                Type = "file"            });            operation.Consumes.Add("multipart/form-data");        }    }}它在 Swagger 启动类中注册:                options.OperationFilter<FileUploadOperationFilter>();因此,来自 IFormFile 的所有字段都消失了,而是有上传文件控件,因此我可以选择“试用”按钮,选择一个文件,但是在按“执行”后,我收到以下错误:web api 本身不会崩溃,也不会抛出任何错误。我在调试期间注意到的 -FileUploadController达到了 的构造函数但没有触发 FileUpload 方法。
查看完整描述

3 回答

?
largeQ

TA贡献2039条经验 获得超7个赞

你能试试这个操作过滤器吗:


/// <summary>

/// Filter to enable handling file upload in swagger

/// </summary>

public class FormFileSwaggerFilter : IOperationFilter

{

    private const string formDataMimeType = "multipart/form-data";

    private static readonly string[] formFilePropertyNames =

        typeof(IFormFile).GetTypeInfo().DeclaredProperties.Select(p => p.Name).ToArray();


    /// <summary>

    /// Applies the specified operation.

    /// </summary>

    /// <param name="operation">The operation.</param>

    /// <param name="context">The context.</param>

    public void Apply(Operation operation, OperationFilterContext context)

    {

        var parameters = operation.Parameters;

        if (parameters == null || parameters.Count == 0) return;


        var formFileParameterNames = new List<string>();

        var formFileSubParameterNames = new List<string>();


        ProcessActionParameters(context, ref formFileParameterNames, ref formFileSubParameterNames);


        if (!formFileParameterNames.Any()) return;


        var consumes = operation.Consumes;

        consumes.Clear();

        consumes.Add(formDataMimeType);


        ProcessParameters(ref parameters, formFileSubParameterNames);


        ProcessFormFileParameters(formFileParameterNames, ref parameters);

    }


    private static void ProcessFormFileParameters(List<string> formFileParameterNames, ref IList<IParameter> parameters)

    {

        foreach (var formFileParameter in formFileParameterNames)

        {

            parameters.Add(new NonBodyParameter()

            {

                Name = formFileParameter,

                Type = "file",

                In = "formData"

            });

        }

    }


    private static void ProcessActionParameters(OperationFilterContext context, ref List<string> formFileParameterNames,

        ref List<string> formFileSubParameterNames)

    {

        foreach (var actionParameter in context.ApiDescription.ActionDescriptor.Parameters)

        {

            var properties =

                actionParameter.ParameterType.GetProperties()

                    .Where(p => p.PropertyType == typeof(IFormFile))

                    .Select(p => p.Name)

                    .ToArray();


            if (properties.Length != 0)

            {

                formFileParameterNames.AddRange(properties);

                formFileSubParameterNames.AddRange(properties);

                continue;

            }


            if (actionParameter.ParameterType != typeof(IFormFile)) continue;

            formFileParameterNames.Add(actionParameter.Name);

        }

    }


    private static void ProcessParameters(ref IList<IParameter> parameters, List<string> formFileSubParameterNames)

    {

        foreach (var parameter in parameters.ToArray())

        {

            if (!(parameter is NonBodyParameter) || parameter.In != "formData") continue;


            if (formFileSubParameterNames.Any(p => parameter.Name.StartsWith(p + "."))

                || formFilePropertyNames.Contains(parameter.Name))

                parameters.Remove(parameter);

        }

    }

}



查看完整回答
反对 回复 2021-11-14
?
喵喔喔

TA贡献1735条经验 获得超5个赞

表单中的键应该与方法中的参数匹配,在过滤器中重命名:


operation.Parameters.Add(new NonBodyParameter()

            {

                Name = "uploadedFile",

                In = "formData",

                Description = "Upload File",

                Required = true,

                Type = "file"

            });


查看完整回答
反对 回复 2021-11-14
?
冉冉说

TA贡献1877条经验 获得超1个赞

通过从参数中删除 IFormFile 上传文件来解决:


    [HttpPost]

[Route(nameof(UploadFile))]

public FileUploadResult UploadFile()

{

    return _FileUploader.UploadFile(Request.Form.Files[0]);

}


查看完整回答
反对 回复 2021-11-14
  • 3 回答
  • 0 关注
  • 351 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信