如何让C#/.NET Core自定义类/结构体在Swagger中呈现为值类型?
解决方案
要让自定义类/结构体在Swagger里呈现为单一值类型(类似DateTime的效果),需要同时搞定JSON序列化逻辑和Swagger Schema的识别配置,下面是具体步骤:
1. 实现自定义类型的JSON序列化转换
首先得让JSON序列化器把你的自定义类型转换成单一值(比如字符串、数字),而非展开它的内部属性。以.NET Core默认的System.Text.Json为例:
假设我们自定义一个Email结构体:
public readonly struct Email { public string Value { get; } public Email(string value) { if (!value.Contains("@")) throw new ArgumentException("无效的邮箱格式"); Value = value; } public override string ToString() => Value; // 可选:实现隐式转换,简化类型使用 public static implicit operator string(Email email) => email.Value; public static implicit operator Email(string value) => new Email(value); }
接着写对应的JSON转换器,控制序列化/反序列化行为:
public class EmailJsonConverter : JsonConverter<Email> { public override Email Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new Email(reader.GetString()!); } public override void Write(Utf8JsonWriter writer, Email value, JsonSerializerOptions options) { writer.WriteStringValue(value.Value); } }
在Program.cs里注册这个转换器:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new EmailJsonConverter()); });
2. 配置Swagger识别自定义类型为值类型
此时序列化逻辑已正常,但Swagger仍会把Email识别为带Value属性的对象,需要修改Swagger的Schema定义:
方式一:使用SchemaFilter
实现一个SchemaFilter来修正Schema:
public class EmailSchemaFilter : ISchemaFilter { public void Apply(OpenApiSchema schema, SchemaFilterContext context) { if (context.Type == typeof(Email)) { schema.Type = "string"; schema.Format = "email"; // 可选:指定格式,让Swagger识别为邮箱类型 schema.Properties.Clear(); schema.Example = new OpenApiString("user@example.com"); } } }
在Swagger配置中注册这个Filter:
builder.Services.AddSwaggerGen(c => { c.SchemaFilter<EmailSchemaFilter>(); // 其他Swagger配置... });
方式二:用属性简化配置
如果不想写Filter,可直接给自定义类型添加SwaggerSchema属性(需引用Swashbuckle.AspNetCore.Annotations包):
using Swashbuckle.AspNetCore.Annotations; [SwaggerSchema(Type = "string", Format = "email", Example = "user@example.com")] public readonly struct Email { // 结构体内容不变... }
3. 验证效果
定义一个测试接口:
[HttpPost] public IActionResult SendEmail([FromBody] EmailRequest request) { return Ok($"发送邮件到:{request.Recipient}"); } public class EmailRequest { public Email Recipient { get; set; } }
此时Swagger文档里的EmailRequest会显示为:
{ "recipient": "user@example.com" }
完全和DateTime的展示逻辑一致,不会展开成嵌套属性结构。
内容的提问来源于stack exchange,提问作者Ben Dickey
相关产品推荐
相关产品推荐

