ASP.NET WebForms下无权限修改JSON.Net时如何自定义第三方类序列化规则
可以通过Json.NET的全局扩展能力调整VendorClassA的序列化/反序列化逻辑,完全满足你提出的所有限制条件,不需要修改第三方代码、Session提供程序或者VendorClassA本身的代码。以下是按优先级排列的可落地方案:
方案1:自定义ContractResolver(最简方案)
Json.NET默认会将实现了IEnumerable接口的类型判定为集合类型,序列化为JSON数组,反序列化时无法映射回原类型。你可以通过自定义ContractResolver强制将VendorClassA按普通对象类型处理,代码如下:
public class IgnoreEnumerableContractResolver : DefaultContractResolver { protected override JsonContract CreateContract(Type objectType) { // 针对VendorClassA强制生成对象契约,不走集合序列化逻辑 if (objectType == typeof(VendorClassA)) { return CreateObjectContract(objectType); } return base.CreateContract(objectType); } }
在站点启动入口(Global.asax的Application_Start方法)注册全局生效的配置:
protected void Application_Start(object sender, EventArgs e) { JsonConvert.DefaultSettings = () => new JsonSerializerSettings { ContractResolver = new IgnoreEnumerableContractResolver() }; }
这个方案不需要额外处理属性读写,Json.NET会自动按照普通对象的规则序列化/反序列化VendorClassA的所有公开成员,完全兼容现有存取逻辑。
方案2:全局注册自定义JsonConverter
如果VendorClassA有特殊的构造逻辑或者非公开成员需要序列化,可以自定义JsonConverter实现完全可控的序列化逻辑:
public class VendorClassAConverter : JsonConverter<VendorClassA> { public override void WriteJson(JsonWriter writer, VendorClassA value, JsonSerializer serializer) { // 将实例的所有需要保留的属性序列化为JSON对象 var jObj = new JObject(); // 示例:序列化所有公开属性,可根据实际需要调整 foreach (var prop in typeof(VendorClassA).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (prop.CanRead) { jObj[prop.Name] = JToken.FromObject(prop.GetValue(value), serializer); } } jObj.WriteTo(writer); } public override VendorClassA ReadJson(JsonReader reader, Type objectType, VendorClassA existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObj = JObject.Load(reader); // 构造VendorClassA实例,无公开构造函数时可通过反射创建 var instance = Activator.CreateInstance<VendorClassA>(); // 给实例属性赋值 foreach (var prop in typeof(VendorClassA).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (prop.CanWrite && jObj.TryGetValue(prop.Name, out var token)) { prop.SetValue(instance, token.ToObject(prop.PropertyType, serializer)); } } return instance; } }
同样在Application_Start中注册:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = { new VendorClassAConverter() } };
方案3:动态给VendorClassA添加序列化特性(兼容强隔离场景)
如果自定义Session提供程序显式指定了JsonSerializerSettings,未使用全局DefaultSettings,可以通过.NET内置的TypeDescriptor机制动态给VendorClassA添加JsonConverter特性,无需修改类源码:
protected void Application_Start(object sender, EventArgs e) { // 动态给VendorClassA添加JsonConverterAttribute TypeDescriptor.AddAttributes(typeof(VendorClassA), new JsonConverterAttribute(typeof(VendorClassAConverter))); }
Json.NET读取类型特性时会自动识别TypeDescriptor添加的动态特性,就算序列化逻辑未使用全局配置也能生效。
以上三种方案都满足所有限制条件:存取Session的对象始终是VendorClassA实例,第三方代码的强转逻辑完全不需要修改,不需要调整Session提供程序的任何代码。优先使用方案1,实现成本最低,兼容性最好。
内容的提问来源于stack exchange,提问作者Ann L.

