在我的服务器端blazor项目(核心3,preview6)中,我试图用我的类的实例调用javascript。您可以通过注入IJSRuntime
并在其上调用InvokeAsync
来做到这一点(请参阅here)。
因为我需要摆脱所有null属性(应该处理我的对象的js库(chartJs)不能处理null值),并且由于我有一些自定义序列化(对于可以具有不同数据类型的枚举),所以我砍掉了它可以与ExpandoObject
一起使用(这不是我的想法,但是可以)。
我首先使用json.net序列化了对象,因此可以定义NullValueHandling = NullValueHandling.Ignore
,因此所有自定义转换器都被使用了。
然后,我再次使用json.net将其解析为ExpandoObject
。我之所以这样做,是因为否则,不在json中的值在c#实例中将为null,但这样就根本不存在它们。
此ExpandoObject
不具有空值,并且具有正确的枚举值,然后用于调用javascript。这样,当到达javascript引擎时就不会有null值。
Since in preview6 json.net isn't used internally anymore和新的json序列化程序(来自System.Text.Json
)无法处理ExpandoObject
,当我从Preview5更新为Preview6时遇到运行时错误,说ExpandoObject
不支持。没什么大不了的,我做了一个函数,将ExpandoObject
转换为Dictionary<string, object>
,可以毫无问题地进行序列化。
阅读this question,以了解有关我如何执行此操作的更多信息,并查看一些示例。如果您不太了解我的所作所为,那么这可能是个好主意。它还包含我将在此处添加的json以及c#模型和其他说明。
这有效,但是我认为也许如果我能够回到json.net,我可以完全删除ExpandoObject
,因为首先它将使用我为特殊枚举编写的自定义转换器,其次我可以全局指定NullValueHandling = NullValueHandling.Ignore
(请问这会有副作用吗?)。
我遵循the ms docs再次使用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
,因为我知道.net的新json序列化器无法处理该问题。正如预期的那样,它引发了异常,并且堆栈跟踪没有显示json.net的迹象。这证实了它实际上并没有像我所说的那样使用json.net。
在System.Text.Json.Serialization.JsonClassInfo.GetElementType中的(Type propertyType,Type parentType,MemberInfo memberInfo) 在System.Text.Json.Serialization.JsonClassInfo.CreateProperty中(类型为声明的PropertyType,类型为runtimePropertyType,PropertyInfo propertyInfo,类型为ParentClassType,JsonSerializerOptions选项) 在System.Text.Json.Serialization.JsonClassInfo.AddProperty(Type propertyType,PropertyInfo propertyInfo,Type classType,JsonSerializerOptions选项) 在System.Text.Json.Serialization.JsonClassInfo..ctor中(类型类型,JsonSerializerOptions选项) 在System.Text.Json.Serialization.JsonSerializerOptions.GetOrAddClass(Type classType) 在System.Text.Json.Serialization.JsonSerializer.GetRuntimeClassInfo(对象值,JsonClassInfo&jsonClassInfo,JsonSerializerOptions选项) 在System.Text.Json.Serialization.JsonSerializer.HandleEnumerable(JsonClassInfo elementClassInfo,JsonSerializerOptions选项,Utf8JsonWriter writer,WriteStack&state)中 在System.Text.Json.Serialization.JsonSerializer.Write(Utf8JsonWriter writer,Int32 flushThreshold,JsonSerializerOptions选项,WriteStack和状态) 在System.Text.Json.Serialization.JsonSerializer.WriteCore(PooledByteBufferWriter输出,对象值,类型类型,JsonSerializerOptions选项) 在System.Text.Json.Serialization.JsonSerializer.WriteCoreString(对象值,类型类型,JsonSerializerOptions选项) 在System.Text.Json.Serialization.JsonSerializer.ToString [TValue](TValue值,JsonSerializerOptions选项)处 在Microsoft.JSInterop.JSRuntimeBase.InvokeAsync [T](字符串标识符,Object []参数) 在ChartJs.Blazor.ChartJS.ChartJsInterop.GetJsonRep(IJSRuntime jSRuntime,对象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
的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
}
}
那么,即使我指示这样做,为什么仍然使用System.Text.Json
而不是Newtonsoft.Json
?我还需要添加什么才能使其使用json.net?
答案 0 :(得分:1)
正如@dbc的注释中正确提到的,IJSRuntime
始终使用System.Text.Json
。我已通过询问asp.net团队对此进行了确认(请参见my github issue)。
这些当然是个坏消息,但实际上没有办法做我想做的事,并且可以确认,asp.net团队不打算添加此功能(再次参见my github feature request)。