You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Swagger UI同时支持JSON请求体格式与文件上传?

解决Swagger UI同时展示JSON请求体与文件选择按钮的问题

针对你使用Swashbuckle.AspNetCore 6.5.0版本时,无法同时展示JSON编辑区域和文件选择按钮的问题,以下是具体实现方案:

1. 定义请求模型与控制器

首先创建包含JSON元数据和文件的请求模型,控制器方法通过[FromForm]接收混合请求:

// 请求模型
public class FileWithJsonRequest
{
    // 存储JSON内容,后续会渲染为JSON编辑器
    public string Metadata { get; set; }
    // 上传的文件
    public IFormFile File { get; set; }
}

// 控制器方法
[HttpPost("upload-with-metadata")]
public IActionResult UploadWithMetadata([FromForm] FileWithJsonRequest request)
{
    // 将Metadata字符串解析为你的业务模型
    var metadataModel = JsonSerializer.Deserialize<YourBusinessMetadataModel>(request.Metadata);
    
    // 处理上传的文件(示例逻辑)
    using var stream = new MemoryStream();
    await request.File.CopyToAsync(stream);
    var fileBytes = stream.ToArray();
    
    return Ok(new { Metadata = metadataModel, FileSize = fileBytes.Length });
}

2. 自定义Swagger过滤器

通过SchemaFilter和OperationFilter修改Swagger的API描述,将请求类型设置为multipart/form-data:

SchemaFilter(标记特殊模型)

public class FileWithJsonSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type == typeof(FileWithJsonRequest))
        {
            // 为模型添加自定义扩展标记,用于后续UI识别
            schema.Extensions.Add("x-is-file-with-json", new OpenApiBoolean(true));
        }
    }
}

OperationFilter(配置请求内容类型)

public class FileWithJsonOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var requestType = context.ApiDescription.ParameterDescriptions
            .FirstOrDefault(p => p.ParameterType == typeof(FileWithJsonRequest))?.ParameterType;
        
        if (requestType == typeof(FileWithJsonRequest))
        {
            // 强制将请求内容类型设置为multipart/form-data
            operation.RequestBody = new OpenApiRequestBody
            {
                Content = new Dictionary<string, OpenApiMediaType>
                {
                    ["multipart/form-data"] = new OpenApiMediaType
                    {
                        Schema = new OpenApiSchema
                        {
                            Type = "object",
                            Properties = new Dictionary<string, OpenApiSchema>
                            {
                                ["Metadata"] = new OpenApiSchema { Type = "string", Format = "json" },
                                ["File"] = new OpenApiSchema { Type = "string", Format = "binary" }
                            },
                            Required = new HashSet<string> { "Metadata", "File" }
                        }
                    }
                },
                Required = true
            };
        }
    }
}

3. 配置Swagger服务

在Program.cs中注册过滤器:

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "你的API名称", Version = "v1" });
    // 添加自定义过滤器
    c.SchemaFilter<FileWithJsonSchemaFilter>();
    c.OperationFilter<FileWithJsonOperationFilter>();
});

4. 自定义Swagger UI渲染逻辑

通过注入自定义JS脚本,将Metadata文本框替换为JSON编辑器:

配置SwaggerUI注入脚本

app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "你的API V1");
    // 注入自定义UI脚本
    c.InjectJavascript("/swagger-ui/custom-file-json-script.js");
});

创建自定义JS文件

在wwwroot/swagger-ui/目录下创建custom-file-json-script.js,内容如下:

window.addEventListener('load', () => {
    // 监听SwaggerUI渲染变化
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            if (mutation.addedNodes.length === 0) return;
            
            // 查找所有Metadata文本框
            const metadataInputs = document.querySelectorAll('input[name="Metadata"]');
            metadataInputs.forEach(input => {
                // 避免重复替换
                if (input.nextElementSibling?.classList.contains('json-editor')) return;
                
                const parentDiv = input.parentElement;
                // 替换文本框为JSON编辑textarea
                parentDiv.innerHTML = `
                    <label for="Metadata">JSON元数据</label>
                    <textarea id="Metadata" name="Metadata" class="json-editor" rows="8" placeholder="输入JSON内容..."></textarea>
                `;
                
                const textarea = parentDiv.querySelector('.json-editor');
                if (!textarea) return;
                
                // 应用SwaggerUI风格样式
                Object.assign(textarea.style, {
                    width: '100%',
                    padding: '10px',
                    border: '1px solid #ccc',
                    borderRadius: '4px',
                    fontFamily: 'monospace'
                });
                
                // 添加JSON格式化功能
                textarea.addEventListener('blur', () => {
                    try {
                        const parsed = JSON.parse(textarea.value);
                        textarea.value = JSON.stringify(parsed, null, 2);
                    } catch (e) {
                        // 无效JSON不处理
                    }
                });
            });
        });
    });

    // 监听SwaggerUI容器
    observer.observe(document.getElementById('swagger-ui'), {
        childList: true,
        subtree: true
    });
});

关键说明

  • 为什么不能用多Content-Type选择:SwaggerUI默认仅支持单Content-Type请求,而multipart/form-data是唯一能同时传输文件和文本(JSON)的格式。
  • 控制器需手动解析JSON:因为Metadata是从表单中接收的字符串,需要自己反序列化为业务模型。

内容的提问来源于stack exchange,提问作者concaho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:17:25