В моем серверном проекте Blazor (ядро 3, preview6) я пытаюсь вызвать javascript с экземпляром моего класса.Вы можете сделать это, введя IJSRuntime
и вызвав InvokeAsync
(см. здесь ).
Потому что мне нужно избавиться от всех нулевых свойств (библиотека js, которая должна обрабатывать мой объект (chartJs), не может обрабатывать нулевые значения) и потому что у меня есть некоторая настраиваемая сериализация (для перечислений, которые могут иметь разные типы данных)Я взломал его для работы с ExpandoObject
(это была не моя идея, но она работает).
Сначала я сериализовал свой объект с помощью json.net, чтобы я мог определить NullValueHandling = NullValueHandling.Ignore
, и поэтому все пользовательские конвертеры были использованы.
Затем я снова использовал json.net, чтобы разобрать его в ExpandoObject
.Я, конечно, сделал это, потому что в противном случае значения, отсутствующие в json, были бы нулевыми в экземпляре c #, но таким образом их вообще нет.
Этот ExpandoObject
, который не имеет нулевых значений и который имеет правильные значения перечисления, затем используется для вызова JavaScript.Таким образом, нет никаких нулевых значений, когда он попадает в движок javascript.
Поскольку в preview6 json.net больше не используется внутри и новый сериализатор json (из System.Text.Json
)не могу обработать ExpandoObject
s, я получил ошибку времени выполнения при обновлении с preview5 до preview6, говоря, что ExpandoObject
не поддерживается.Ничего страшного, я сделал функцию для преобразования ExpandoObject
в Dictionary<string, object>
, который можно без проблем сериализовать.
Читать этот вопрос , чтобы узнать больше о том, как я это сделали увидеть несколько примеров.Это может быть хорошей идеей, если вы не совсем понимаете, что я сделал.Также он содержит json, который я добавлю сюда, а также модель c # и другие объяснения.
Это работает, но я подумал, что, возможно, если я смогу вернуться на json.net, я мог бы полностьюудалите ExpandoObject
, потому что, во-первых, он будет использовать пользовательские преобразователи, которые я написал для своих специальных перечислений, а во-вторых, я мог бы указать NullValueHandling = NullValueHandling.Ignore
глобально (ps. это будет иметь побочные эффекты?).
Я следовал документам MS о том, как снова использовать json.net, и добавил это к методу ConfigureServies
(services.AddRazorPages()
уже был там):
services.AddRazorPages()
.AddNewtonsoftJson(o =>
{
o.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
o.SerializerSettings.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy(true, false)
};
});
К сожалению, это не сработало, и прямой вызов js с объектом привел к тому же json (см. Ниже), как и прежде, чем я добавил это.
Затем я попытался использовать ExpandoObject
напрямую, потому что знал, что новый сериализатор json из .net не может с этим справиться.Как и ожидалось, возникло исключение, и на трассировке стека нет признаков json.net.Это подтверждает, что он на самом деле не использует json.net, как я сказал.
в System.Text.Json.Serialization.JsonClassInfo.GetElementType (тип propertyType, тип parentType, MemberInfo memberInfo) в System.Text.Json.Serialization.JsonClassInfo.CreateProperty (тип объявленный, тип свойства)PropertyInfo, propertyInfo, тип parentClassType, параметры JsonSerializerOptions) в System.Text.Json.Serialization.JsonClassInfo.AddProperty (тип propertyType, PropertyInfo propertyInfo, тип classType, параметры JsonSerializerOptions) в System.Text.Json.Serialization.fo.Inlass.JClass, Параметры JsonSerializerOptions) в System.Text.Json.Serialization.JsonSerializerOptions.GetOrAddClass (тип classType) в System.Text.Json.Serialization.JsonSerializer.GetRuntimeClassInfo (значение объекта, JsonClassInfo. jsonClassizer.erial.erial.Onsign.OnSense.Station) опции JsonClassizer.erial.son.sonE.JsonSerializer.HandleEnumerable (JsonClassInfo elementClassInfo, параметры JsonSerializerOptions, средство записи Utf8JsonWriter, WriteStack & state) в System.Text.Json.Serialization.в System.Text.Json.Serialization.JsonSerializer.WriteCoreString (значение объекта, тип Type, параметры JsonSerializerOptions) в System.Text.Json.Serialization.JsonSerializer.ToString [TValue] (значение TValue, параметры JsonSerializerOptions) в Microsoft.JSInteraseJR.InvokeAsync [T] (строковый идентификатор, аргументы объекта []) в ChartJs.Blazor.ChartJS.ChartJsInterop.GetJsonRep (IJSRuntime jSRuntime, Object obj)
Затем я также попытался просто изменить параметры изнормальный сериализатор, чтобы увидеть, изменит ли это что-нибудь.Я использовал это вместо AddNewtonsoftJson
:
services.AddRazorPages()
.AddJsonOptions(o => o.JsonSerializerOptions.IgnoreNullValues = true);
Интересно, что это все равно дало мне тот же результат.
Я добавлю полученный json вместе с тем, что должно быть произведено.Вы также можете найти это в вопросе CodeReview, который я упоминал ранее.
Я получаю следующий json:
Он остается неизменным, когда
- Я ничего не указываю в методе
ConfigureServices
. - Я указываю использовать от
Newtonsoft.Json
до AddNewtonsoftJson
. - Я указываю
JsonOptions
от .net до AddJsonOptions
.
{
"options": {
"someInt": 2,
"someString": null,
"axes": [
{
"someString": null
},
{
"someString": "axisString"
}
]
},
"data": {
"data": [
1,
2,
3,
4,
5
],
"someString": "asdf",
"someStringEnum": {} <-- this is one of those special enums with a custom converter
}
}
Вот что я должен получить.Обратите внимание, что все нулевые значения удалены и используется пользовательский конвертер.Я смог получить это только с помощью моего хакерского решения, которое использует ExpandoObject
.
{
"options": {
"someInt": 2,
"axes": [
{},
{
"someString": "axisString"
}
]
},
"data": {
"data": [
1,
2,
3,
4,
5
],
"someString": "asdf",
"someStringEnum": "someTestThing" <-- this is one of those special enums with a custom converter
}
}
Так почему же оно все еще использует System.Text.Json
вместо Newtonsoft.Json
, хотя я и дал команду?Что еще я должен добавить, чтобы он использовал json.net?