.NET 7中F#自定义JsonConverter失效问题求助
项目从.NET 5/6升级到.NET 7后,原本正常工作的F#自定义JsonConverter突然失效,返回DTO时抛出F#判别式联合序列化不支持的异常。
自定义JsonConverter代码
type RouteCheckConverter() = inherit JsonConverter<RouteCheckResponse>() override _.Read(reader, _, _): RouteCheckResponse = match reader.GetInt32() with | 200 -> RouteOk | 301 -> RouteRedirect | 404 -> RouteNotFound | _ -> failwithf "Unknown route check response" override _.Write (writer, r, _): unit = match r with | RouteOk -> writer.WriteNumberValue 200 | RouteRedirect -> writer.WriteNumberValue 301 | RouteNotFound -> writer.WriteNumberValue 404
判别式联合定义
type RouteCheckResponse = | RouteOk | RouteRedirect | RouteNotFound
使用转换器的DTO类
type RouteCheckResultDTO = { page: ProductPageDTO option redirectTo: string option [<JsonConverter(typeof<RouteCheckConverter>)>] response: RouteCheckResponse }
抛出的异常信息
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.NotSupportedException: F# discriminated union serialization is not supported. Consider authoring a custom converter for the type.
at System.Text.Json.Serialization.Converters.FSharpTypeConverterFactory.CreateConverter(Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.Serialization.JsonConverterFactory.GetConverterInternal(Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetConverterForType(Type typeToConvert, JsonSerializerOptions options, Boolean resolveJsonConverterAttribute)
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateJsonTypeInfo(Type type, JsonSerializerOptions options)
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type type)
at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory)
at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.Configure()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.InitializePropertyCache()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.g__ConfigureLocked|143_0()
--- End of stack trace from previous location ---
原因与解决方案
这不是.NET 7的Bug,而是.NET 7中System.Text.Json新增了FSharpTypeConverterFactory,它会优先处理F#判别式联合类型,导致DTO属性上的JsonConverter注解被忽略。
有两种可行的解决方法:
- 全局注册自定义转换器:在配置JsonSerializerOptions时,将自定义转换器添加到Converters集合,覆盖默认的F#转换器工厂处理逻辑:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(RouteCheckConverter()) }) - 为判别式联合类型直接添加注解:将
JsonConverter注解移至判别式联合定义上,而非DTO的属性上:[<JsonConverter(typeof<RouteCheckConverter>)>] type RouteCheckResponse = | RouteOk | RouteRedirect | RouteNotFound
两种方法均可让自定义转换器正常生效,推荐第二种,更贴合类型本身的序列化规则。
内容的提问来源于stack exchange,提问作者eastwing

