简体   繁体   English

IJSRuntime 忽略服务器端 blazor 项目中的自定义 json 序列化程序

[英]IJSRuntime ignores custom json serializer in server side blazor project

In my server side blazor project (core 3, preview6) I'm trying to invoke javascript with an instance of my class.在我的服务器端 blazor 项目(核心 3,preview6)中,我试图用我的类的实例调用 javascript。 You can do this by injecting a IJSRuntime and calling InvokeAsync on it (see here ).您可以通过注入IJSRuntime并对其调用InvokeAsync来完成此操作(请参阅此处)。

Because I need to get rid of all the null properties (the js library that should handle my object (chartJs) cannot handle null values) and because I have some custom serialization (for enums that can have different datatypes), I hacked it to work with an ExpandoObject (that was not my idea but it works).因为我需要摆脱所有 null 属性(应该处理我的对象(chartJs)的 js 库无法处理 null 值)并且因为我有一些自定义序列化(对于可以具有不同数据类型的枚举),我对其进行了修改使用ExpandoObject (这不是我的想法,但它有效)。

I first serialized my object with json.net so I could define NullValueHandling = NullValueHandling.Ignore and so all the custom converters got used.我首先用 json.net 序列化了我的对象,这样我就可以定义NullValueHandling = NullValueHandling.Ignore ,所以所有的自定义转换器都被使用了。

Then I used json.net again to parse it to an ExpandoObject .然后我再次使用 json.net 将其解析为ExpandoObject I of course did that because otherwise the values that aren't in the json would be null in the c# instance but this way they aren't present at all.我当然这样做了,因为否则不在 json 中的值在 c# 实例中将为 null,但这样它们根本不存在。

This ExpandoObject which doesn't have the null values and which has the correct enum values, is then used to invoke the javascript.这个没有空值且具有正确枚举值的ExpandoObject然后用于调用 javascript。 This way there are no null values when it gets to the javascript engine.这样,当它到达 javascript 引擎时就没有空值。

Since in preview6 json.net isn't used internally anymore and the new json serializer (from System.Text.Json ) cannot handle ExpandoObject s, I got a runtime error when I updated from preview5 to preview6, saying that ExpandoObject isn't supported.由于在 preview6 中 json.net 不再内部使用,并且新的 json 序列化程序(来自System.Text.Json )无法处理ExpandoObject s,当我从 preview5 更新到 preview6 时出现运行时错误,说不支持ExpandoObject . No big deal, I made a function to convert an ExpandoObject to a Dictionary<string, object> which can be serialized without a problem.没什么大不了的,我做了一个函数来将一个ExpandoObject转换为一个Dictionary<string, object> ,它可以毫无问题地序列化。

Read this question to see more about how I did this and to see some examples.阅读此问题以了解有关我如何做到这一点的更多信息并查看一些示例。 This might be a good idea if you don't quite understand what I did.如果你不太明白我做了什么,这可能是个好主意。 Also it contains the json that I will add in here as well along with the c# model and other explanations.它还包含我将在此处添加的 json 以及 c# 模型和其他解释。

This works but I thought that maybe if I would be able to get back to json.net I could completely remove the ExpandoObject because firstly it would use the custom converters I wrote for my special enums and secondly I could specify NullValueHandling = NullValueHandling.Ignore globally (ps. would this have sideeffects?).这有效,但我认为,如果我能够回到 json.net,我可以完全删除ExpandoObject因为首先它会使用我为我的特殊枚举编写的自定义转换器,其次我可以指定NullValueHandling = NullValueHandling.Ignore全局(ps。这会有副作用吗?)。

I followed the ms docs on how to use json.net again and added this to the ConfigureServies method ( services.AddRazorPages() was already there):我再次遵循有关如何使用 json.net 的 ms 文档并将其添加到ConfigureServies方法( services.AddRazorPages()已经存在):

services.AddRazorPages()
    .AddNewtonsoftJson(o =>
    {
        o.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        o.SerializerSettings.ContractResolver = new DefaultContractResolver
        {
            NamingStrategy = new CamelCaseNamingStrategy(true, false)
        };
    });

Sadly it did not work and directly invoking js with the object led to the exact same json (see below) as before I added this.遗憾的是,它不起作用,直接用对象调用 js 会导致与添加此之前完全相同的 json(见下文)。

Then I tried using an ExpandoObject directly because I knew the new json serializer from .net can't handle that.然后我尝试直接使用ExpandoObject因为我知道来自 .net 的新 json 序列化程序无法处理。 As expected it threw an exception and the stacktrace shows no signs of json.net.正如预期的那样,它抛出了一个异常,并且堆栈跟踪没有显示 json.net 的迹象。 This confirms that it's not actually using json.net like I told it to.这证实了它实际上并没有像我告诉它的那样使用 json.net。

at System.Text.Json.Serialization.JsonClassInfo.GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo) at System.Text.Json.Serialization.JsonClassInfo.CreateProperty(Type declaredPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonClassInfo.AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonClassInfo..ctor(Type type, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonSerializerOptions.GetOrAddClass(Type classType) at System.Text.Json.Serialization.JsonSerializer.GetRuntimeClassInfo(Object value, JsonClassInfo& jsonClassInfo, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonSerializer.HandleEnumerable(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.Serializatio在 System.Text.Json.Serialization.JsonClassInfo.GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo) at System.Text.Json.Serialization.JsonClassInfo.CreateProperty(Type declarationPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)在 System.Text.Json.Serialization.JsonClassInfo.AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options) 在 System.Text.Json.Serialization.JsonClassInfo..ctor(Type type, JsonSerializerOptions options) 在 System.Text。 Json.Serialization.JsonSerializerOptions.GetOrAddClass(Type classType) 在 System.Text.Json.Serialization.JsonSerializer.GetRuntimeClassInfo(Object value, JsonClassInfo& jsonClassInfo, JsonSerializerOptions options) 在 System.Text.Json.Serialization.JsonSerializer.HandleEnumerable(JsonClassInfo 元素ClassInfos选项、Utf8JsonWriter 编写器、WriteStack& 状态)在 System.Text.Json.Serializatio n.JsonSerializer.Write(Utf8JsonWriter writer, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonSerializer.WriteCore(PooledByteBufferWriter output, Object value, Type type, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonSerializer.WriteCoreString(Object value, Type type, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonSerializer.ToString[TValue](TValue value, JsonSerializerOptions options) at Microsoft.JSInterop.JSRuntimeBase.InvokeAsync[T](String identifier, Object[] args) at ChartJs.Blazor.ChartJS.ChartJsInterop.GetJsonRep(IJSRuntime jSRuntime, Object obj) n.JsonSerializer.Write(Utf8JsonWriter writer, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonSerializer.WriteCore(PooledByteBufferWriter output, Object value, Type type, JsonSerializerOptions options) at System.Text.Json。 Serialization.JsonSerializer.WriteCoreString(Object value, Type type, JsonSerializerOptions options) at System.Text.Json.Serialization.JsonSerializer.ToString[TValue](TValue value, JsonSerializerOptions options) at Microsoft.JSInterop.JSRuntimeBase.InvokeAsync[T](String标识符, Object[] args) 在 ChartJs.Blazor.ChartJS.ChartJsInterop.GetJsonRep(IJSRuntime jSRuntime, Object obj)

I then also tried just changing the options from the normal serializer to see if that would change anything.然后,我还尝试仅更改普通序列化程序中的选项,以查看是否会改变任何内容。 I used this instead of AddNewtonsoftJson :我用这个代替AddNewtonsoftJson

services.AddRazorPages()
    .AddJsonOptions(o => o.JsonSerializerOptions.IgnoreNullValues = true);

Interestingly this still gave me the same result.有趣的是,这仍然给了我相同的结果。

I will add the json that got produced along with what should be produced.我将添加生成的 json 以及应该生成的内容。 You can also find this in the CodeReview question I mentioned earlier.您也可以在我之前提到的 CodeReview 问题中找到这一点。

The following json is what I get:以下json是我得到的:

It stays the same when当它保持不变时

  • I don't specify anything in the ConfigureServices method.我没有在ConfigureServices方法中指定任何内容。
  • I specify to use Newtonsoft.Json through AddNewtonsoftJson .我指定通过AddNewtonsoftJson使用Newtonsoft.Json
  • I specify the JsonOptions from .net through AddJsonOptions .我指定的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
    }
}

This is what I should get.这是我应该得到的。 Notice all the null values are removed and the custom converter is used.请注意,所有空值都被删除并使用了自定义转换器。 I was only able to get this with my hacky solution that uses the ExpandoObject .我只能通过我使用ExpandoObject hacky解决方案来获得这个。

{
    "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
    }
}

So why is it still using System.Text.Json instead of Newtonsoft.Json even though I instructed it to?那么为什么即使我指示它仍然使用System.Text.Json而不是Newtonsoft.Json呢? What else do I have to add to make it use json.net?我还需要添加什么才能使用 json.net?

As correctly mentioned in the comments by @dbc, IJSRuntime always uses System.Text.Json .正如@dbc 在评论中正确提到的那样, IJSRuntime始终使用System.Text.Json I have confirmed this by asking the asp.net team about it (see my github issue ).我已经通过询问 asp.net 团队确认了这一点(请参阅我的 github 问题)。

I submitted a github feature request which might make this possible in future .NET versions.我提交了一个github 功能请求,这可能会在未来的 .NET 版本中实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM