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

如何在.NET中用Newtonsoft JSON.NET序列化类属性及自定义属性?

解决JSON.NET序列化时保留自定义[Encrypted]特性的方案

核心结论

Newtonsoft JSON.NET没有直接内置的实现来自动将自定义特性序列化到JSON中,但可以通过自定义ContractResolver实现动态识别任意类上的[Encrypted]特性,并在序列化时添加标记信息,满足接收方识别加密属性的需求。

实现方案

方式一:将加密属性值包装为带标记的对象

这种方式会把加密属性的原值包装成包含加密标识的对象,接收方可以直接通过对象结构识别加密字段。

1. 定义包装类

public class EncryptedValue
{
    public string Value { get; set; }
    public string EncryptionKey { get; set; }
}

2. 实现自定义ContractResolver与转换器

public class EncryptedContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        
        // 检查当前属性是否带有Encrypted特性
        var encryptedAttr = member.GetCustomAttribute<EncryptedAttribute>();
        if (encryptedAttr != null)
        {
            // 为该属性指定自定义转换器,实现值的包装
            property.Converter = new EncryptedValueConverter(encryptedAttr.Key);
        }
        
        return property;
    }
}

public class EncryptedValueConverter : JsonConverter
{
    private readonly string _encryptionKey;

    public EncryptedValueConverter(string encryptionKey)
    {
        _encryptionKey = encryptionKey;
    }

    public override bool CanConvert(Type objectType)
    {
        // 只处理字符串类型的属性(可根据实际需求扩展)
        return objectType == typeof(string);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var encryptedValue = new EncryptedValue
        {
            Value = (string)value,
            EncryptionKey = _encryptionKey
        };
        serializer.Serialize(writer, encryptedValue);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 反序列化时直接返回原始值(可根据需求添加解密逻辑)
        var encryptedValue = serializer.Deserialize<EncryptedValue>(reader);
        return encryptedValue?.Value;
    }
}

方式二:添加独立的加密标记字段

如果希望保留属性原值的结构,可通过添加额外字段标记该属性是否需要加密,比如为Address属性添加IsAddressEncrypted字段。

实现自定义ContractResolver

public class EncryptedMetadataContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        var extendedProperties = new List<JsonProperty>(properties);
        
        foreach (var property in properties)
        {
            var encryptedAttr = property.Member.GetCustomAttribute<EncryptedAttribute>();
            if (encryptedAttr != null)
            {
                // 创建标记字段,格式为"Is{PropertyName}Encrypted"
                var metadataProperty = new JsonProperty
                {
                    PropertyName = $"Is{property.PropertyName}Encrypted",
                    Readable = true,
                    Writable = false,
                    ValueProvider = new ConstantValueProvider(true),
                    DefaultValueHandling = DefaultValueHandling.Ignore
                };
                extendedProperties.Add(metadataProperty);
            }
        }
        
        return extendedProperties;
    }
}

public class ConstantValueProvider : IValueProvider
{
    private readonly object _fixedValue;

    public ConstantValueProvider(object value)
    {
        _fixedValue = value;
    }

    public object GetValue(object target) => _fixedValue;
    public void SetValue(object target, object value)
    {
        // 标记字段为只读,无需实现赋值逻辑
    }
}

使用示例

序列化时指定自定义的ContractResolver即可:

var person = new Person
{
    Id = 1,
    FirstName = "John",
    LastName = "Doe",
    Address = "123 Main St",
    Phone = "555-1234",
    IdentityDetails = "XYZ123"
};

// 使用方式一的序列化配置
var settings1 = new JsonSerializerSettings
{
    ContractResolver = new EncryptedContractResolver()
};
string wrappedJson = JsonConvert.SerializeObject(person, settings1);

// 使用方式二的序列化配置
var settings2 = new JsonSerializerSettings
{
    ContractResolver = new EncryptedMetadataContractResolver()
};
string markedJson = JsonConvert.SerializeObject(person, settings2);

说明

  • 两种方案都支持动态处理任意类,无需修改原有类的代码结构
  • 方式一的JSON结构更直观,适合接收方直接解析加密信息;方式二保留了原始属性值结构,适合需要兼容非加密场景的需求
  • 反序列化时可根据业务需求,在转换器或ContractResolver中添加解密、验证等逻辑

内容的提问来源于stack exchange,提问作者Neeraj Kumar Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 01:22:37