aspnetcore: A published blazor wasm app throws a serialization error "Unhandled exception rendering component: ConstructorContainsNullParameterNames"
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
An error is thrown when making a JS interop call in a published blazor wasm app that should serialize a KeyValuePair
value.
This seems to be related to trimming as running this with things like dotnet run --configuration Release
works as expected, but publishing the app starts the trimmer by default.
In addition, using an anonymous type instead of KeyValuePair
works without any errors.
[!NOTE] I tried to disable the trimming, but the error is still present. Any suggestions on how to do that will be helpful - this might turn out to be another issue though.
Expected Behavior
No error is thrown.
Steps To Reproduce
- Clone https://github.com/Stamo-Gochev/blazor-issue-wasm-serialization
- Change directory to https://github.com/Stamo-Gochev/blazor-issue-wasm-serialization/tree/master/BlazorissueWasmSerialization/BlazorissueWasmSerialization
- Run
dotnet publish --configuration Release
- Go to
BlazorissueWasmSerialization/BlazorissueWasmSerialization/bin/Release/net8.0/publish
- Run
dotnet BlazorissueWasmSerialization.dll
- Click the “Show issue button”
Exceptions (if any)
Exception
blazor.web.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair`2[System.String,System.String] SerializationNotSupportedParentType, System.Object Path: $.
System.NotSupportedException: ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair`2[System.String,System.String] SerializationNotSupportedParentType, System.Object Path: $.
---> System.NotSupportedException: ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair`2[System.String,System.String]
at System.Text.Json.ThrowHelper.ThrowNotSupportedException_ConstructorContainsNullParameterNames(Type )
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.PopulateParameterInfoValues(JsonTypeInfo )
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateTypeInfoCore(Type , JsonConverter , JsonSerializerOptions )
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateJsonTypeInfo(Type , JsonSerializerOptions )
at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetTypeInfo(Type , JsonSerializerOptions )
at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type )
at System.Text.Json.JsonSerializerOptions.CachingContext.CreateCacheEntry(Type type, CachingContext context)
--- End of stack trace from previous location ---
at System.Text.Json.JsonSerializerOptions.CachingContext.CacheEntry.GetResult()
at System.Text.Json.JsonSerializerOptions.CachingContext.GetOrAddTypeInfo(Type , Boolean )
at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type , Boolean , Nullable`1 , Boolean , Boolean )
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureSynchronized|172_0()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.EnsureConfigured()
at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type , Boolean , Nullable`1 , Boolean , Boolean )
at System.Text.Json.WriteStackFrame.InitializePolymorphicReEntry(Type , JsonSerializerOptions )
at System.Text.Json.Serialization.JsonConverter.ResolvePolymorphicConverter(Object , JsonTypeInfo , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonConverter`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryWrite(Utf8JsonWriter , Object& , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.Converters.DictionaryOfTKeyTValueConverter`3[[System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].OnWriteResume(Utf8JsonWriter , Dictionary`2 , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonDictionaryConverter`3[[System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].OnTryWrite(Utf8JsonWriter , Dictionary`2 , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonConverter`1[[System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryWrite(Utf8JsonWriter , Dictionary`2& , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonConverter`1[[System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryWriteAsObject(Utf8JsonWriter , Object , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonConverter`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryWrite(Utf8JsonWriter , Object& , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.Converters.ArrayConverter`2[[System.Object[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].OnWriteResume(Utf8JsonWriter , Object[] , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonCollectionConverter`2[[System.Object[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].OnTryWrite(Utf8JsonWriter , Object[] , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonConverter`1[[System.Object[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryWrite(Utf8JsonWriter , Object[]& , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.JsonConverter`1[[System.Object[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].WriteCore(Utf8JsonWriter , Object[]& , JsonSerializerOptions , WriteStack& )
Exception_EndOfInnerExceptionStack
at System.Text.Json.ThrowHelper.ThrowNotSupportedException(WriteStack& , NotSupportedException )
at System.Text.Json.Serialization.JsonConverter`1[[System.Object[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].WriteCore(Utf8JsonWriter , Object[]& , JsonSerializerOptions , WriteStack& )
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1[[System.Object[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Serialize(Utf8JsonWriter , Object[]& , Object )
at System.Text.Json.JsonSerializer.WriteString[Object[]](Object[]& , JsonTypeInfo`1 )
at System.Text.Json.JsonSerializer.Serialize[Object[]](Object[] , JsonSerializerOptions )
at Microsoft.JSInterop.JSRuntime.InvokeAsync[IJSVoidResult](Int64 , String , CancellationToken , Object[] )
at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[Microsoft.JSInterop.Infrastructure.IJSVoidResult, Microsoft.JSInterop, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime , String , Object[] )
at BlazorissueWasmSerialization.Client.Pages.Home.OnButtonShowIssueClick()
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task , ComponentState )
.NET Version
8.0.100
Anything else?
No response
About this issue
- Original URL
- State: open
- Created 8 months ago
- Reactions: 9
- Comments: 27 (14 by maintainers)
This seems to be a regression in the linker in fact.
@javiercn
Yes, it works with previous versions - .NET 6.0 and .NET 7.0.
The Home.razor page and the JS file can be pasted in a standalone .NET 6.0 and .NET 7.0 projects for comparison.
Regarding the suggestions:
this is possible, but the change in the behavior looks more or less like a regression to me - it is not clear why
KeyValuePair
was serializeable before and not now.As .NET 8.0 is a major release, I can accept a public issue that states that
KeyValuePair
is no longer serializable when linking is enabled, but I couldn’t find such an issue, which is why it seems like a regression to me.This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. If it is closed, feel free to comment when you are able to provide the additional information and we will re-investigate.
See our Issue Management Policies for more information.
I’m getting the identical exception, also in a published WASM app serializing a KeyValue pair. Error does not happen locally. In my case this is the Telerik blazor grid serializing or deserializing a KeyValue pair under the hood that is related to a default date filter in the grid. As a result this error appears on any grid that has a filterable date column.
Yes it has, I tested it on the same exact project just with different targets, on .NET 7 it works fine, but on .NET 8 an exception occurs ☹️
https://github.com/dotnet/aspnetcore/assets/47293197/278e079c-90b4-4550-b614-1513e8118e21
here’s the project repo: https://github.com/SaifAqqad/blazor-bug-test
Imo even if this is the intended behavior of the trimmer, there should be a built-in exclusion of certain types (serialization, etc) for wasm projects
@taylorchasewhite If the issue happens at the linking stage, there are two possibilities:
In most situations, the member is simply not being preserved, and that matters most when you are using types from the framework, since gestures that you might expect will result in them being preserved (like being passed to a JS interop call) won’t actually do so.
In those situations, the descriptor file is the way to go.
Blazor predates many of the linking/trimming work (in fact, it spearheaded it) and does not support full trimming. For example, we don’t trim customers dlls to prevent issues like this.
While I believe this is a regression, I am going to suggest we patch it on our side, since I think it’ll be easier.
It’s straightforward to repro. Details below performed using SDK 8.0.100 on Windows 11:
Replace contents of
Counter.razor
in client with the following:If you run server and visit counter page it will work as expected:
Afterwards publish the app and run the exe:
On visiting counter page you will get
System.NotSupportedException
as detailed by OP.No. It means that using reflection-based serialization in trimmed applications is not reliable and can result in multiple failures like the one reported here. This is a problem inherent to using dynamic member access via reflection in trimmed applications and there’s not much that can be done about it other than adding manual annotations to work around the issues that pop up. Our recommendation is to switch to the source generator if you must use a trimmed app, see this article for more details.
Duplicate of dotnet/runtime#74141, https://github.com/dotnet/runtime/issues/94806 and https://github.com/dotnet/runtime/issues/81709.
The reason this error shows up on serialization traces as well as deserialization is because of this breaking change. I would recommend either switching to the source generator or applying a
DynamicDependency
attribute on the affected types (see https://github.com/passwordless-lib/fido2-net-lib/commit/1fbfb25cb9f53a8795ab952698dcc6493df1add3 for an example).