Это мои типы:
[<DataContract>]
type AreaCodeSingleResponse =
{ [<field:DataMember(Name = "id")>]
Id : string
[<field:DataMember(Name = "code")>]
Code : string
[<field:DataMember(Name = "name")>]
Name : string }
[<DataContract>]
type AreaCodeListResponse =
{
[<field:DataMember(Name = "areacode_list")>]
AreaCodeList : List<AreaCodeSingleResponse> }
Это образец данных:
{
"areacode_list": [
{
"id": "00447",
"code": "07",
"name": "UK Mobile",
"order_column": "_00447"
},
{
"id": "0044113",
"code": "0113",
"name": "Leeds",
"order_column": "0044113"
}
]
}
Это код десериализации, где вызывается передача типа AreaCodeListResponse:
member __.ReturnDataToType<'T>() =
__.ReturnData
|> JsonConvert.DeserializeObject<'T>
До того, как я обновился до DotNet6, все работало нормально и возвращало список данных. После этого он терпит неудачу и возвращает пустой список. Ошибок нет, но список пуст.
Это не удается для всех моих других вызовов десериализации с использованием класса и других типов.
Изменилось ли что-нибудь, о чем мне нужно знать? Я не эксперт F#, просто работаю над каким-то устаревшим кодом.
Нет, определенно используется JSON.net, это специально указано в коде.
У меня нет f# на .NET 6 для тестирования, но что, если вы измените [<field:DataMember(Name = "areacode_list")>]
на [<DataMember(Name = "areacode_list")>]
?
На самом деле, критическое изменение, похоже, происходит при переходе с .net 6.0 на 7.0. У меня ваш подход работает с версиями Newtonsoft.Json 13.0.2, 12.0.3 и 11.0.2 (более ранние не пробовал) в .net 6.0, но уже не в .net 7.0. Каков результат dotnet --version
в вашем окружении?
Судя по всему, изменилось поведение в том, как среда выполнения .Net обрабатывает OptionalFieldAttribute
(используется как field:
в F#) в .Net 7 (в сочетании с записями F#). При просмотре документации OptionalFieldAttribute он не должен иметь значимого эффекта в контексте сериализации/десериализации JSON и, следовательно, должен быть удален. Следующий код работает, создавая список экземпляров записей AreaCodeSingleResponse. Минимальная модификация, позволяющая заставить код в вопросе работать, — удалить OptionalFieldAttribute
из поля AreaCodeList
.
#r "nuget:Newtonsoft.Json,Version=13.0.2"
open System.Runtime.Serialization
open Newtonsoft.Json
[<DataContract>]
type AreaCodeSingleResponse =
{
[<DataMember(Name = "id")>]
Id : string
[<DataMember(Name = "code")>]
Code : string
[<DataMember(Name = "name")>]
Name : string
}
[<DataContract>]
type AreaCodeListResponse =
{
//Remove the OptionalFieldAttribute:
//[<field:DataMember(Name = "areacode_list")>]
[<DataMember(Name = "areacode_list")>]
AreaCodeList : List<AreaCodeSingleResponse>
}
let ReturnData = """{
"areacode_list": [
{
"id": "00447",
"code": "07",
"name": "UK Mobile",
"order_column": "_00447"
},
{
"id": "0044113",
"code": "0113",
"name": "Leeds",
"order_column": "0044113"
}
]
}"""
ReturnData |> JsonConvert.DeserializeObject<AreaCodeListResponse> |> printf "%A"
Вопрос, почему происходит такое изменение поведения при переходе с .Net runtime 6.0.201 на .Net 7.0.101, остается открытым.
Есть ли шанс, что вы перешли на System.Text.Json из Newtonsoft, не осознавая этого? Вы не говорите, с какой версии вы обновились, но в asp.net-core-3.0 Microsoft отказалась от Json.NET и перешла на свой новый сериализатор JSON, System.Text.Json. См.: Куда делся IMvcBuilder AddJsonOptions в .Net Core 3.0? . И System.Text.Json плохо поддерживает f#, см., например. Сериализация членов Record с помощью System.Text.Json и github.com/dotnet/runtime/issues/55744.