如何创建ASP.NET Core(6/7)Web API控制器接收含变长基类型列表的模型?
问题分析与解决思路
这个方案完全可行,问题出在ASP.NET Core默认模型绑定/序列化逻辑的限制,以及Swagger对可变参数构造函数的识别不足。下面是具体的排查和解决步骤:
1. 先明确核心矛盾
假设你的请求模型是类似这样的(以C#为例):
public class MyRequest { public string[] Items { get; } // 可变参数构造函数 public MyRequest(params string[] items) { Items = items; } }
这种情况下,默认的JSON序列化器(System.Text.Json)不会自动将JSON结构映射到构造函数的可变参数上,Swagger也无法正确生成对应的请求格式示例。
2. 具体解决方法
方法一:添加无参构造函数+可写属性(最简单直接)
给模型补充无参构造函数,并将属性改为可写,让模型绑定器能正常赋值:
public class MyRequest { public string[] Items { get; set; } // 保留可变参数构造函数用于单元测试 public MyRequest(params string[] items) { Items = items; } // 添加无参构造函数供API模型绑定使用 public MyRequest() { } }
此时Swagger会自动识别Items数组,对应的JSON请求格式为:
{ "items": ["value1", "value2"] }
方法二:自定义JSON转换器(保留只读属性场景)
如果必须保留只读属性和可变参数构造函数,可以给模型添加自定义JSON转换器,明确序列化/反序列化规则:
public class MyRequestConverter : JsonConverter<MyRequest> { public override MyRequest Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 将JSON数组直接转成字符串数组传入构造函数 var items = JsonSerializer.Deserialize<string[]>(ref reader, options); return new MyRequest(items); } public override void Write(Utf8JsonWriter writer, MyRequest value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value.Items, options); } }
然后在模型上标记转换器:
[JsonConverter(typeof(MyRequestConverter))] public class MyRequest { public string[] Items { get; } public MyRequest(params string[] items) { Items = items; } }
这种情况下Swagger可能无法自动生成正确示例,需要手动添加请求示例配置:
[SwaggerRequestExample(typeof(MyRequest), typeof(MyRequestExample))] public IActionResult Post([FromBody] MyRequest request) { // 业务逻辑 } public class MyRequestExample : IExamplesProvider<MyRequest> { public MyRequest GetExamples() { return new MyRequest("value1", "value2"); } }
对应的JSON请求体可以直接传数组:
["value1", "value2"]
3. 优化Swagger识别能力
在.NET 6+中,可以通过以下配置让Swagger更好地识别带参数的构造函数,但对可变参数(params)的支持仍有限,建议配合前面的模型调整使用:
builder.Services.AddSwaggerGen(options => { options.SupportNonNullableReferenceTypes(); options.UseAllOfToExtendReferenceSchemas(); // 启用构造函数类型识别 options.SelectSubTypesUsing(baseType => baseType.Assembly.GetTypes().Where(type => baseType.IsAssignableFrom(type))); });
总结
你遗漏的是ASP.NET Core模型绑定对只读属性+可变参数构造函数的支持限制,以及Swagger对这类特殊构造函数的识别缺陷。通过调整模型结构或添加自定义转换器,就能顺利解决Swagger请求格式的问题。
内容的提问来源于stack exchange,提问作者BerggreenDK
相关产品推荐
相关产品推荐

