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

序列化Windows-1252编码时遇Newtonsoft.Json序列化异常求助

问题描述

尝试将System.Text.Encoding.CodePages包中的Windows-1252编码序列化为JSON时,抛出异常:

Newtonsoft.Json.JsonSerializationException: Error getting value from 'WindowsCodePage' on 'System.Text.SBCSCodePageEncoding'

但UTF8等内置编码可以正常完成序列化操作,复现代码如下:

using System;
using System.Text;
using Newtonsoft.Json;
                    
public class Program
{
    public static void Main()
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        var workingEncoding = Encoding.UTF8;
        var notWorkingEncoding = Encoding.GetEncoding("windows-1252");
        
        Console.WriteLine(workingEncoding.EncodingName);
        Console.WriteLine(notWorkingEncoding.EncodingName);
        Console.WriteLine();
        
        var workingSerialized = JsonConvert.SerializeObject(workingEncoding);
        Console.WriteLine(workingSerialized);
        Console.WriteLine();
        
        var notWorkingSerialized = JsonConvert.SerializeObject(notWorkingEncoding);
        Console.WriteLine(notWorkingSerialized);
    }
}

问题原因

通过CodePagesEncodingProvider获取的Windows-1252编码属于SBCSCodePageEncoding类型,该类型的WindowsCodePage是内部属性。Newtonsoft.Json默认序列化时会通过反射遍历所有属性,尝试访问这个内部属性时触发权限异常。而UTF8这类内置编码属于UTF8Encoding,不存在此类内部属性的访问问题。


解决方法

方法1:自定义JsonConverter序列化关键信息

创建自定义转换器,只序列化编码的核心标识信息,避免访问内部属性,同时支持反序列化:

using Newtonsoft.Json;
using System.Text;

public class EncodingConverter : JsonConverter<Encoding>
{
    public override void WriteJson(JsonWriter writer, Encoding value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        writer.WritePropertyName("CodePage");
        writer.WriteValue(value.CodePage);
        writer.WritePropertyName("EncodingName");
        writer.WriteValue(value.EncodingName);
        writer.WritePropertyName("WebName");
        writer.WriteValue(value.WebName);
        writer.WriteEndObject();
    }

    public override Encoding ReadJson(JsonReader reader, Type objectType, Encoding existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jo = Newtonsoft.Json.Linq.JObject.Load(reader);
        var codePage = (int)jo["CodePage"];
        return Encoding.GetEncoding(codePage);
    }
}

使用示例:

var settings = new JsonSerializerSettings();
settings.Converters.Add(new EncodingConverter());

var serialized = JsonConvert.SerializeObject(notWorkingEncoding, settings);
Console.WriteLine(serialized);

// 反序列化示例
var deserializedEncoding = JsonConvert.DeserializeObject<Encoding>(serialized, settings);

方法2:直接序列化编码标识(最简方案)

如果只需要保存编码的标识信息,无需序列化整个对象,可以直接序列化WebName或CodePage,反序列化时重新获取编码:

// 序列化
var serialized = JsonConvert.SerializeObject(notWorkingEncoding.WebName);

// 反序列化
var webName = JsonConvert.DeserializeObject<string>(serialized);
var encoding = Encoding.GetEncoding(webName);

方法3:忽略序列化错误(不推荐)

通过配置序列化设置忽略无法访问的成员和错误,这种方式可能丢失属性信息,仅作为临时替代方案:

var settings = new JsonSerializerSettings
{
    Error = (sender, args) => args.ErrorContext.Handled = true,
    ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver
    {
        IgnoreSerializableInterface = true,
        IgnoreSerializableAttribute = true
    }
};

var serialized = JsonConvert.SerializeObject(notWorkingEncoding, settings);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:52:42