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

如何在C# Minimal API返回的JSON中自动添加类名为type属性?

自动为C# Minimal API返回的JSON添加type属性

解决方案:自定义JSON转换器工厂

要实现无需在每个类中手动添加Type属性,通过配置System.Text.Json序列化器自动注入type字段,可以通过自定义JsonConverterFactory实现,具体步骤如下:

1. 实现转换器工厂与具体转换器

创建通用转换器工厂,拦截自定义类的序列化过程,自动添加type字段:

using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

public class TypePropertyConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        // 仅处理自定义类,排除基本类型、字符串、枚举、匿名类型等
        return !typeToConvert.IsPrimitive && 
               typeToConvert != typeof(string) && 
               !typeToConvert.IsEnum &&
               !typeToConvert.IsAnonymousType();
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var converterType = typeof(TypePropertyConverter<>).MakeGenericType(typeToConvert);
        return (JsonConverter)Activator.CreateInstance(converterType)!;
    }
}

// 辅助扩展方法:判断是否为匿名类型
public static class TypeExtensions
{
    public static bool IsAnonymousType(this Type type)
    {
        return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false) &&
               type.IsGenericType && type.Name.Contains("AnonymousType") &&
               (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) &&
               type.Attributes.HasFlag(TypeAttributes.NotPublic);
    }
}

// 具体类型的转换器
public class TypePropertyConverter<T> : JsonConverter<T>
{
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 反序列化时忽略type字段,正常解析原有属性
        return JsonSerializer.Deserialize<T>(ref reader, options)!;
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        // 序列化对象原有属性(移除当前转换器避免递归调用)
        var modifiedOptions = new JsonSerializerOptions(options);
        modifiedOptions.Converters.RemoveAll(c => c.GetType() == typeof(TypePropertyConverter<T>));
        JsonSerializer.Serialize(writer, value, modifiedOptions);

        // 添加type字段,值为当前类的名称
        writer.WriteString("type", typeof(T).Name);

        writer.WriteEndObject();
    }
}

2. 配置Minimal API的JSON序列化器

在WebApplication.CreateBuilder阶段,将自定义转换器添加到JsonOptions中:

var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<JsonOptions>(options =>
{
    options.SerializerOptions.Converters.Add(new TypePropertyConverterFactory());
});

var app = builder.Build();

// 示例API端点
app.MapGet("/user", () => new User { Name = "Jason" });

app.Run();

3. 测试效果

定义无需手动添加Type属性的User类:

public class User
{
    public string Name { get; set; }
}

调用/user端点后,返回的JSON将自动包含type字段:

{
   "name": "Jason",
   "type": "User"
}

扩展:自定义type字段的值

如果需要指定type字段的自定义值(而非类名),可通过自定义特性实现:

  1. 定义特性类:
[AttributeUsage(AttributeTargets.Class)]
public class JsonTypeAttribute : Attribute
{
    public string TypeName { get; }
    public JsonTypeAttribute(string typeName) => TypeName = typeName;
}
  1. 在实体类上标记特性:
[JsonType("CustomUser")]
public class User
{
    public string Name { get; set; }
}
  1. 修改转换器的Write方法,读取特性值:
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
    writer.WriteStartObject();

    var modifiedOptions = new JsonSerializerOptions(options);
    modifiedOptions.Converters.RemoveAll(c => c.GetType() == typeof(TypePropertyConverter<T>));
    JsonSerializer.Serialize(writer, value, modifiedOptions);

    // 优先读取自定义特性的TypeName,否则用类名
    var typeAttr = typeof(T).GetCustomAttribute<JsonTypeAttribute>();
    var typeName = typeAttr?.TypeName ?? typeof(T).Name;
    writer.WriteString("type", typeName);

    writer.WriteEndObject();
}

此时返回的JSON将是:

{
   "name": "Jason",
   "type": "CustomUser"
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:25:14