如何将Newtonsoft JSON默认设置限定到自身程序集以避免影响第三方组件?
我来帮你梳理几个可行的解决方案,既能实现字符串自动修剪,又不会影响第三方程序集:
1. 给自定义转换器加程序集判断,限定作用范围
既然全局注册会影响第三方,那可以在你的StringTrimmer转换器里,只对自己应用程序集内的类型进行修剪操作。修改转换器的ReadJson方法,判断目标类型所属的程序集是不是你自己的:
public class StringTrimmer : JsonConverter<string> { // 替换成你应用里任意一个根类的类型,用来获取程序集 private readonly Assembly _appAssembly = typeof(YourAppStartupClass).Assembly; public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer) { var rawValue = reader.Value?.ToString(); // 只处理自己程序集内的类型对应的字符串属性 if (objectType.Assembly == _appAssembly) { return rawValue?.Trim(); } // 第三方类型直接返回原字符串,不修剪 return rawValue; } public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer) { writer.WriteValue(value?.Trim()); } }
这样全局注册后,只有你自己程序集里的类型会被修剪,第三方程序集的序列化/反序列化不受影响。
2. 放弃全局默认设置,使用自定义Settings实例
全局的JsonConvert.DefaultSettings会影响所有使用默认配置的地方,包括第三方库。更好的方式是定义自己的专属JsonSerializerSettings,只在你自己的代码里使用:
// 可以放在一个静态类里复用,避免重复创建 public static class AppJsonSettings { public static readonly JsonSerializerSettings Instance = new JsonSerializerSettings { Converters = new List<JsonConverter> { new StringTrimmer() } // 其他你需要的配置,比如日期格式、忽略空值等 }; }
然后在你需要序列化/反序列化的地方,显式传入这个自定义配置:
// 反序列化 var myAppModel = JsonConvert.DeserializeObject<MyAppModel>(jsonString, AppJsonSettings.Instance); // 序列化 var serializedJson = JsonConvert.SerializeObject(myAppModel, AppJsonSettings.Instance);
第三方库使用JsonConvert默认方法时,会用它自己的配置,不会被你的转换器干扰。
3. 不依赖JsonConvert,通过Model Binding实现自动修剪(适合Web应用)
如果你的应用是ASP.NET Core Web项目,完全可以绕过Json转换器,在模型绑定阶段就自动修剪所有输入字符串。实现一个自定义的模型绑定器:
public class TrimmedStringModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var rawValue = valueProviderResult.FirstValue; if (string.IsNullOrEmpty(rawValue)) { bindingContext.Result = ModelBindingResult.Success(null); return Task.CompletedTask; } // 修剪字符串 bindingContext.Result = ModelBindingResult.Success(rawValue.Trim()); return Task.CompletedTask; } }
然后在Startup里注册这个绑定器,让它处理所有字符串类型的绑定:
services.AddControllers(options => { // 插入到绑定器列表的最前面,确保优先使用 options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(string), new TrimmedStringModelBinder())); });
这种方式更彻底,不管是Form表单输入还是JSON请求体,只要是字符串类型的参数/属性都会被自动修剪,而且完全不影响第三方库的Json处理。
额外:如果用System.Text.Json替代Newtonsoft.Json
如果你已经迁移到.NET Core/.NET 5+的System.Text.Json,也可以类似地实现转换器并限定作用范围,或者使用自定义的JsonSerializerOptions实例,和上面的思路一致:
public class StringTrimmerConverter : JsonConverter<string> { private readonly Assembly _appAssembly = typeof(YourAppRootClass).Assembly; public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rawValue = reader.GetString(); if (typeToConvert.Assembly == _appAssembly) { return rawValue?.Trim(); } return rawValue; } public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) { writer.WriteStringValue(value?.Trim()); } }
然后在自己的代码里使用自定义options:
var options = new JsonSerializerOptions(); options.Converters.Add(new StringTrimmerConverter()); var myModel = JsonSerializer.Deserialize<MyAppModel>(json, options);
总结一下,最推荐的是方案2(自定义Settings实例)或者方案3(Model Binding),前者灵活可控,后者适合Web场景更彻底。方案1作为全局注册的折中方案也可以,但需要注意程序集判断的准确性。
内容的提问来源于stack exchange,提问作者user10843855

