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

如何将带数据注解的.NET Core模型类序列化指定JSON格式?

我来分享一个高效且可复用的方案,完美匹配你要的自定义JSON序列化需求,同时还能把反射的性能开销控制在合理范围内。

核心思路

我们的实现分为三个关键步骤:

  1. 缓存反射结果:每个模型类只做一次反射解析,后续直接复用缓存的元数据,彻底避免重复反射的性能损耗
  2. 解析数据注解:把Required、DataType、MaxLength等注解映射到你需要的type和validations字段
  3. 生成目标JSON结构:将解析后的元数据转换成指定格式的JSON输出
完整代码实现

1. 元数据缓存与解析工具类

这个类负责反射解析模型属性,并把结果缓存起来,是性能优化的核心:

using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Text.Json;

public static class ModelMetadataCache
{
    // 缓存字典:key为模型类型,value为预解析好的属性元数据列表
    private static readonly Dictionary<Type, List<PropertyMetadata>> _metadataCache = new();

    // 获取指定模型的元数据(优先从缓存取,没有则解析并缓存)
    public static List<PropertyMetadata> GetModelMetadata<T>()
    {
        var modelType = typeof(T);
        if (_metadataCache.TryGetValue(modelType, out var cachedMetadata))
        {
            return cachedMetadata;
        }

        var properties = modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        var metadataList = new List<PropertyMetadata>();

        foreach (var prop in properties)
        {
            var propertyMeta = new PropertyMetadata
            {
                PropertyName = prop.Name.ToCamelCase(),
                DefaultValue = GetDefaultValue(prop.PropertyType)
            };

            // 解析DataType注解,映射到目标type字段
            var dataTypeAttr = prop.GetCustomAttribute<DataTypeAttribute>();
            propertyMeta.Type = dataTypeAttr != null 
                ? MapDataTypeToCamelCase(dataTypeAttr.DataType) 
                : MapClrTypeToTypeString(prop.PropertyType);

            // 解析验证规则
            var requiredAttr = prop.GetCustomAttribute<RequiredAttribute>();
            propertyMeta.Validations["required"] = requiredAttr != null;

            var maxLengthAttr = prop.GetCustomAttribute<MaxLengthAttribute>();
            if (maxLengthAttr != null)
            {
                propertyMeta.Validations["maxLength"] = maxLengthAttr.Length;
            }

            metadataList.Add(propertyMeta);
        }

        _metadataCache[modelType] = metadataList;
        return metadataList;
    }

    // 将DataType枚举值转为小写驼峰格式
    private static string MapDataTypeToCamelCase(DataType dataType)
    {
        return dataType switch
        {
            DataType.Text => "text",
            DataType.EmailAddress => "email",
            DataType.MultilineText => "multilineText",
            DataType.DateTime => "dateTime",
            // 可根据需求扩展更多DataType映射
            _ => "text"
        };
    }

    // 当没有DataType注解时,根据CLR类型推断type字段
    private static string MapClrTypeToTypeString(Type type)
    {
        if (type == typeof(int) || type == typeof(long) || type == typeof(decimal))
            return "number";
        if (type == typeof(bool))
            return "boolean";
        if (type == typeof(DateTime))
            return "dateTime";
        return "text";
    }

    // 获取属性类型的默认值
    private static object GetDefaultValue(Type type)
    {
        return type.IsValueType ? Activator.CreateInstance(type) : null;
    }
}

// 辅助类:存储单个属性的元数据
public class PropertyMetadata
{
    public string PropertyName { get; set; }
    public string Type { get; set; }
    public object DefaultValue { get; set; }
    public Dictionary<string, object> Validations { get; set; } = new();
}

// 扩展方法:PascalCase转camelCase
public static class StringExtensions
{
    public static string ToCamelCase(this string input)
    {
        if (string.IsNullOrEmpty(input)) return input;
        return char.ToLowerInvariant(input[0]) + input[1..];
    }
}

2. 序列化工具类

负责把元数据转换成你需要的JSON结构:

public static class CustomModelSerializer
{
    public static string SerializeToTargetJson<T>()
    {
        var metadata = ModelMetadataCache.GetModelMetadata<T>();
        var jsonStructure = new Dictionary<string, object>();

        foreach (var propMeta in metadata)
        {
            jsonStructure[propMeta.PropertyName] = new
            {
                value = propMeta.DefaultValue,
                type = propMeta.Type,
                validations = propMeta.Validations
            };
        }

        // 配置JSON序列化选项,保证格式美观且符合驼峰命名
        var serializeOptions = new JsonSerializerOptions
        {
            WriteIndented = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        return JsonSerializer.Serialize(jsonStructure, serializeOptions);
    }
}

3. 使用示例

假设你的模型类是:

public class ContactFormModel
{
    [Required] [DataType(DataType.Text)]
    public string Name { get; set; }
    [Required, DataType(DataType.EmailAddress)]
    public string Email { get; set; }
    [Required] [DataType(DataType.Text)]
    public string Subject { get; set; }
    [Required] [MaxLength(500)]
    [DataType(DataType.MultilineText)]
    public string Message { get; set; }
    [Required] [DataType(DataType.DateTime)]
    public DateTime DateOfBirth { get; set; }
    public int AnyNumber { get; set; }
}

调用序列化方法:

var resultJson = CustomModelSerializer.SerializeToTargetJson<ContactFormModel>();
Console.WriteLine(resultJson);

输出的JSON会完全匹配你要求的结构(修正了示例中的语法错误):

{
  "name": {
    "value": "",
    "type": "text",
    "validations": {
      "required": true
    }
  },
  "email": {
    "value": "",
    "type": "email",
    "validations": {
      "required": true
    }
  },
  "subject": {
    "value": "",
    "type": "text",
    "validations": {
      "required": true
    }
  },
  "message": {
    "value": "",
    "type": "multilineText",
    "validations": {
      "required": true,
      "maxLength": 500
    }
  },
  "dateOfBirth": {
    "value": "0001-01-01T00:00:00",
    "type": "dateTime",
    "validations": {
      "required": true
    }
  },
  "anyNumber": {
    "value": 0,
    "type": "number",
    "validations": {
      "required": false
    }
  }
}
性能与扩展说明
  • 反射性能优化:每个模型类只做一次反射解析,后续调用直接从内存缓存取结果,几乎消除了反射的性能开销
  • 可扩展性:如果需要支持更多数据注解(比如MinLength、Range),只需要在GetModelMetadata方法中添加对应的解析逻辑即可
  • 自定义映射:MapDataTypeToCamelCase和MapClrTypeToTypeString方法可以根据你的需求自由修改映射规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 13:02:33