IJSRuntime игнорирует пользовательский сериализатор json в проекте сервера Blazor - PullRequest
2 голосов
/ 06 июля 2019

В моем серверном проекте 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?

1 Ответ

1 голос
/ 08 июля 2019

Как правильно указано в комментариях @dbc, IJSRuntime всегда использует System.Text.Json. Я подтвердил это, спросив об этом команду asp.net (см. моя проблема с github ).

Это, конечно, плохие новости, но на самом деле нет никакого способа делать то, что я хочу, и подтверждается, что команда asp.net не намерена добавлять эту функцию (снова, см. мой запрос на функцию github ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...