带依赖注入的System.Text.Json字符串转换器使用时抛异常求助
问题原因
你遇到的System.InvalidOperationException是因为[JsonConverter]特性要求目标转换器必须具备公共无参构造函数,但你的TranslatableJsonConverter仅提供了带IHttpContextAccessor参数的构造函数,System.Text.Json无法直接实例化它。同时,你已通过IConfigureOptions全局注册了转换器,但属性上的特性优先级高于全局配置,框架会优先尝试实例化特性指定的转换器,最终抛出异常。
解决方案
方案1:移除属性特性,依赖全局注册(适用于所有string类型需转换的场景)
如果你的需求是所有string类型属性都要应用该转换逻辑,直接移除DTO属性上的[JsonConverter(typeof(TranslatableJsonConverter))]特性即可。全局注册的转换器会自动生效,且能正确获取注入的IHttpContextAccessor。
修改后的DTO:
public record DriverBehaviourFamilyCountersDto { public string Name { get; set; } public IEnumerable<BehaviourCounterDto> Behaviours { get; set; } }
方案2:针对特定属性配置转换器(适用于仅部分属性需转换的场景)
如果只想让Name这类特定属性应用转换逻辑,不要用[JsonConverter]特性,而是通过自定义JsonTypeInfoResolver为目标属性指定依赖注入的转换器:
- 创建自定义类型信息解析器:
public class CustomJsonTypeInfoResolver : DefaultJsonTypeInfoResolver { private readonly IHttpContextAccessor _httpContextAccessor; public CustomJsonTypeInfoResolver(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { var jsonTypeInfo = base.GetTypeInfo(type, options); // 为目标DTO的Name属性添加转换器 if (type == typeof(DriverBehaviourFamilyCountersDto)) { var nameProperty = jsonTypeInfo.Properties.FirstOrDefault(p => p.Name == nameof(DriverBehaviourFamilyCountersDto.Name)); if (nameProperty != null) { nameProperty.CustomConverter = new TranslatableJsonConverter(_httpContextAccessor); } } // 可添加其他需要转换的属性逻辑 return jsonTypeInfo; } }
- 在Startup中配置使用该解析器:
services.AddHttpContextAccessor(); services.AddSingleton<CustomJsonTypeInfoResolver>(); services.Configure<JsonOptions>(options => { options.JsonSerializerOptions.TypeInfoResolver = services.BuildServiceProvider().GetRequiredService<CustomJsonTypeInfoResolver>(); });
- 移除DTO属性上的
[JsonConverter]特性,保持DTO简洁:
public record DriverBehaviourFamilyCountersDto { public string Name { get; set; } public IEnumerable<BehaviourCounterDto> Behaviours { get; set; } }
方案3:添加无参构造函数(不推荐,服务定位器模式)
如果不想修改注册方式,可给转换器添加无参构造函数,通过静态持有类获取IHttpContextAccessor:
public class TranslatableJsonConverter : JsonConverter<string> { private readonly IHttpContextAccessor _httpContextAccessor; // 供特性使用的无参构造函数 public TranslatableJsonConverter() { _httpContextAccessor = HttpContextAccessorHolder.HttpContextAccessor; } // 供依赖注入使用的构造函数 public TranslatableJsonConverter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } // 原Read、Write方法实现... } // 静态持有IHttpContextAccessor实例 public static class HttpContextAccessorHolder { public static IHttpContextAccessor HttpContextAccessor { get; set; } } // 在Startup中初始化Holder services.AddHttpContextAccessor(); var httpContextAccessor = services.BuildServiceProvider().GetRequiredService<IHttpContextAccessor>(); HttpContextAccessorHolder.HttpContextAccessor = httpContextAccessor;
此方式虽能解决问题,但引入了静态依赖,不符合依赖注入最佳实践,仅作临时方案。
内容的提问来源于stack exchange,提问作者ciolo
相关产品推荐
相关产品推荐

