C#中如何对静态类JsonSerializer进行依赖注入?
对System.Text.Json进行依赖注入的最佳实践
你的思路方向是对的,但现有方案存在几个明显问题:
settings用object类型缺乏类型安全,调用时必须强制转换,容易引发运行时错误- 接口方法设计不够灵活,没有利用泛型避免装箱操作
- 没有通过DI管理序列化配置,每次调用都传参数冗余繁琐
下面是更合理的实现方案,兼顾类型安全、可扩展性和DI友好性:
1. 定义类型安全的序列化接口
把参数换成具体的JsonSerializerOptions,同时提供泛型重载优化性能:
public interface ISerializer { // 泛型序列化,避免装箱,支持自定义选项 string Serialize<T>(T value, JsonSerializerOptions? options = null); // 对象序列化,兼容非泛型场景 string Serialize(object value, JsonSerializerOptions? options = null); // 泛型反序列化,支持自定义选项 T? Deserialize<T>(string json, JsonSerializerOptions? options = null); }
2. 实现System.Text.Json适配类
通过构造函数注入默认序列化选项,让DI统一管理配置:
public class SystemTextJsonSerializer : ISerializer { private readonly JsonSerializerOptions _defaultOptions; public SystemTextJsonSerializer(JsonSerializerOptions defaultOptions) { _defaultOptions = defaultOptions ?? throw new ArgumentNullException(nameof(defaultOptions)); } public string Serialize<T>(T value, JsonSerializerOptions? options = null) { return JsonSerializer.Serialize(value, options ?? _defaultOptions); } public string Serialize(object value, JsonSerializerOptions? options = null) { return JsonSerializer.Serialize(value, options ?? _defaultOptions); } public T? Deserialize<T>(string json, JsonSerializerOptions? options = null) { return JsonSerializer.Deserialize<T>(json, options ?? _defaultOptions); } }
3. 注册依赖注入
在项目的DI容器中注册默认配置和序列化器(以.NET 6+为例):
// 注册全局默认的JsonSerializerOptions,按需配置规则 builder.Services.AddSingleton<JsonSerializerOptions>(new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = false, IgnoreNullValues = true // 其他自定义配置... }); // 注册序列化器实现 builder.Services.AddSingleton<ISerializer, SystemTextJsonSerializer>();
4. 业务代码中使用
直接通过构造函数注入ISerializer即可,既可以用默认配置,也能临时传自定义选项:
public class MessageSender { private readonly ISerializer _serializer; public MessageSender(ISerializer serializer) { _serializer = serializer; } public void SendMessage(Message message) { // 使用全局默认配置序列化 string json = _serializer.Serialize(message); // 临时使用自定义选项(比如格式化输出) var customOptions = new JsonSerializerOptions { WriteIndented = true }; string prettyJson = _serializer.Serialize(message, customOptions); // 后续发送逻辑... } }
5. 切换序列化库(比如Newtonsoft.Json)
只要实现同一个ISerializer接口,就能无缝替换,业务代码无需修改:
public class NewtonsoftJsonSerializer : ISerializer { private readonly JsonSerializerSettings _defaultSettings; public NewtonsoftJsonSerializer(JsonSerializerSettings defaultSettings) { _defaultSettings = defaultSettings ?? throw new ArgumentNullException(nameof(defaultSettings)); } public string Serialize<T>(T value, JsonSerializerOptions? options = null) { // 可根据需求转换System.Text.Json选项到Newtonsoft配置,或直接用默认 return JsonConvert.SerializeObject(value, _defaultSettings); } public string Serialize(object value, JsonSerializerOptions? options = null) { return JsonConvert.SerializeObject(value, _defaultSettings); } public T? Deserialize<T>(string json, JsonSerializerOptions? options = null) { return JsonConvert.DeserializeObject<T>(json, _defaultSettings); } }
注册时替换实现即可:
builder.Services.AddSingleton<JsonSerializerSettings>(new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore }); builder.Services.AddSingleton<ISerializer, NewtonsoftJsonSerializer>();
6. 测试场景使用
可以用Mock工具(比如Moq)模拟ISerializer,或者用自定义选项验证序列化逻辑:
[Test] public void SendMessage_ShouldCallSerialization() { // Mock序列化器 var mockSerializer = new Mock<ISerializer>(); var testMessage = new Message { Id = 1, Content = "Test Content" }; mockSerializer.Setup(s => s.Serialize(testMessage)).Returns("{\"id\":1,\"content\":\"Test Content\"}"); var sender = new MessageSender(mockSerializer.Object); sender.SendMessage(testMessage); // 验证序列化方法被正确调用 mockSerializer.Verify(s => s.Serialize(testMessage), Times.Once); }
方案优势
- 类型安全:避免了
object类型的强制转换,减少运行时异常 - 配置集中:全局序列化规则由DI统一管理,无需重复配置
- 高度可扩展:切换序列化库只需替换实现类,业务逻辑无侵入
- 测试友好:轻松Mock或自定义配置,验证不同场景下的序列化行为
内容的提问来源于stack exchange,提问作者FIlipson
相关产品推荐
相关产品推荐

