Skip to content

A published blazor wasm app throws a serialization error "Unhandled exception rendering component: ConstructorContainsNullParameterNames" #52947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
Stamo-Gochev opened this issue Nov 15, 2023 · 80 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components feature-trimming triaged
Milestone

Comments

@Stamo-Gochev
Copy link

Stamo-Gochev commented Nov 15, 2023

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.

blazor-issue-wasm-serialization

Expected Behavior

No error is thrown.

Steps To Reproduce

  1. Clone https://github.com/Stamo-Gochev/blazor-issue-wasm-serialization
  2. Change directory to https://github.com/Stamo-Gochev/blazor-issue-wasm-serialization/tree/master/BlazorissueWasmSerialization/BlazorissueWasmSerialization
  3. Run dotnet publish --configuration Release
  4. Go to BlazorissueWasmSerialization/BlazorissueWasmSerialization/bin/Release/net8.0/publish
  5. Run dotnet BlazorissueWasmSerialization.dll
  6. 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

@Stamo-Gochev Stamo-Gochev changed the title A published blazor wasm app throws a serialization error A published blazor wasm app throws a serialization error "Unhandled exception rendering component: ConstructorContainsNullParameterNames" Nov 15, 2023
@MackinnonBuck MackinnonBuck added this to the 8.0.x milestone Nov 15, 2023
@hexpoint
Copy link

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.

@mkArtakMSFT mkArtakMSFT added bug This issue describes a behavior which is not expected - a bug. and removed investigate labels Nov 20, 2023
@javiercn
Copy link
Member

@Stamo-Gochev has this ever worked in a previous version of Blazor?

What I suspect is happening is that the KeyValuePair is being linked out. That's because the constructor and other elements are not being preserved. It works with an anonymous type because that type is created within the app assembly and Blazor doesn't serialize that.

If the members are used elsewhere in the app, the issue will go away, but seems that they are only being used during serialization. You can use https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0#root-descriptors and https://github.com/dotnet/runtime/blob/main/docs/tools/illink/data-formats.md#descriptor-format to teach the linker not to strip away members from the type.

If you are still running into issues after taking those steps, let us know, it might be a different linker issue.

@taylorchasewhite
Copy link

@javiercn I have an application that began exhibiting this problem upon upgrading to .NET 8. I didn’t do too much research as I figured you all would hash this bug out, but if you’re under the impression this is not a new issue/not planning to be addressed soon I can also do more digging.

@javiercn javiercn removed this from the 8.0.x milestone Nov 23, 2023
@ghost
Copy link

ghost commented Nov 23, 2023

Hi @Stamo-Gochev. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

@javiercn
Copy link
Member

@taylorchasewhite If the issue happens at the linking stage, there are two possibilities:

  • The type is not being preserved; this requires an individual case analysis to determine whether it's by design or whether there is an issue with any of our annotations.
  • The type is being correctly told to be preserved, but despite that, there are some issues. In that case, it can be a bug in the linker, but with the info collected we can point that out to the linker folks and they can further investigate.

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.

@SaifAqqad
Copy link

has this ever worked in a previous version of Blazor?

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 ☹️

out.mp4

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

@ghost
Copy link

ghost commented Nov 27, 2023

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.

@Stamo-Gochev
Copy link
Author

Stamo-Gochev commented Nov 28, 2023

@javiercn

@Stamo-Gochev has this ever worked in a previous version of Blazor?

What I suspect is happening is that the KeyValuePair is being linked out. That's because the constructor and other elements are not being preserved. It works with an anonymous type because that type is created within the app assembly and Blazor doesn't serialize that.

If the members are used elsewhere in the app, the issue will go away, but seems that they are only being used during serialization. You can use https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0#root-descriptors and https://github.com/dotnet/runtime/blob/main/docs/tools/illink/data-formats.md#descriptor-format to teach the linker not to strip away members from the type.

If you are still running into issues after taking those steps, let us know, it might be a different linker issue.

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:

If the members are used elsewhere in the app, the issue will go away, but seems that they are only being used during serialization. You can use https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0#root-descriptors and https://github.com/dotnet/runtime/blob/main/docs/tools/illink/data-formats.md#descriptor-format to teach the linker not to strip away members from the type.

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.

@javiercn
Copy link
Member

This seems to be a regression in the linker in fact.

@ghost ghost added the untriaged label Nov 29, 2023
@javiercn javiercn transferred this issue from dotnet/aspnetcore Nov 29, 2023
@ghost
Copy link

ghost commented Nov 29, 2023

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

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.

blazor-issue-wasm-serialization

Expected Behavior

No error is thrown.

Steps To Reproduce

  1. Clone https://github.com/Stamo-Gochev/blazor-issue-wasm-serialization
  2. Change directory to https://github.com/Stamo-Gochev/blazor-issue-wasm-serialization/tree/master/BlazorissueWasmSerialization/BlazorissueWasmSerialization
  3. Run dotnet publish --configuration Release
  4. Go to BlazorissueWasmSerialization/BlazorissueWasmSerialization/bin/Release/net8.0/publish
  5. Run dotnet BlazorissueWasmSerialization.dll
  6. 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

Author: Stamo-Gochev
Assignees: javiercn
Labels:

bug, area-System.Text.Json

Milestone: -

@eiriktsarpalis
Copy link
Member

Duplicate of dotnet/runtime#74141, dotnet/runtime#94806 and dotnet/runtime#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 passwordless-lib/fido2-net-lib@1fbfb25 for an example).

@ghost ghost removed the untriaged label Nov 29, 2023
@SaifAqqad
Copy link

The reason this error shows up on serialization traces as well as deserialization is because of this breaking change.

Does this mean that system.text.json doesn't support de/serializing KeyValuePair? Since this is what this issue is about.

I still think this should be looked into more, especially for built-in types like KeyValuePair.

I would recommend either switching to the source generator or applying a DynamicDependency attribute on the affected types

How is it acceptable that serializing such simple types would need this special handling, it sounds like a nightmare tbh.

Throwing attributes around as a fix for such things is not acceptable imo.

@eiriktsarpalis
Copy link
Member

The reason this error shows up on serialization traces as well as deserialization is because of this breaking change.

Does this mean that system.text.json doesn't support de/serializing KeyValuePair? Since this is what this issue is about.

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.

@hoangdovan
Copy link

@eiriktsarpalis I have same problem after upgrade to .Net 8. As you explained, we need to handle this problem by changing our code, and .Net will not support anymore like previous .Net 7 version?

@hoangdovan
Copy link

@SaifAqqad @Stamo-Gochev any work around for this matter? I have same problem! Thanks!

@eiriktsarpalis
Copy link
Member

@hoangdovan The fundamental issue is that trimming and reflection are fundamentally incompatible. There's nothing that we can do about this in the System.Text.Json layer other than recommend switching to the source generator which is trimming-safe.

@Stamo-Gochev
Copy link
Author

hoangdovan

@SaifAqqad @Stamo-Gochev any work around for this matter? I have same problem! Thanks!

It still requires changing your code though and whether you need to serialize a KeyValuePair in several places or if you can replace it with another type.

One option is to create a custom serializer, another one is to map it to something like:

someKeyValuePair.Select(x => new { key = x.Key, value = x.Value })...

which follows the structure of a JSON-serialized KeyValuePair.

@hoangdovan
Copy link

@Stamo-Gochev Thank you. In my case, I create a custom class replace for .Net KeyPairValue to fix this error!

@ghostinside
Copy link

8.0.6 still there

ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair2[System.String,System.Collections.Generic.IEnumerable1[System.String]]

@ghostinside
Copy link

source of exception:

Console.WriteLine(JsonSerializer.Serialize(response.Content.Headers));

@rblanca
Copy link

rblanca commented Jul 6, 2024

Yeap confirmed tuple is getting the same error only on WASM

@mguinness
Copy link

Current workaround is to set keep-metadata parametername on the linker, see #52947 (comment).

@thirstyape
Copy link

Why wait for a fix that might not make it into .NET 8 at all? Here's a laughably simple workaround if you turn off trimming.

Just replace KeyValuePair with KeyValuePairSerializer in your deserialization calls and then call .ToKeyValuePair or if you're in a list .Select(x => x.ToKeyValuePair).ToList(). Same idea can be done for the various Tuple<T> iterations.

using System.Text.Json.Serialization;

public class KeyValuePairSerializer<TKey, TValue>
{
	public KeyValuePairSerializer() { }

	public KeyValuePairSerializer(TKey key, TValue value)
	{
		Key = key;
		Value = value;
	}

	public TKey Key { get; set; }

	public TValue Value { get; set; }

	[JsonIgnore]
	public KeyValuePair<TKey, TValue> ToKeyValuePair => new(Key, Value);
}

@mguinness
Copy link

FWIW the issue still persists with the release of VS 2022 (17.12) and .NET 9

@nrhoffmann
Copy link

nrhoffmann commented Jan 1, 2025

@vitek-karas what's the impact in terms of size that you expect from using something like <_ExtraTrimmerArgs>--keep-metadata parametername</_ExtraTrimmerArgs>.

This is very anecdotal but it only added 1MB to my 40MB app.

@danroth27 danroth27 removed the Docs This issue tracks updating documentation label Jan 13, 2025
@danroth27
Copy link
Member

@lewing @javiercn It seems like users are still hitting issue with the latest bits. Do we need to retriage this issue for servicing?

@danroth27 danroth27 removed this from the .NET 10 Planning milestone Feb 3, 2025
@danroth27
Copy link
Member

danroth27 commented Feb 3, 2025

Removing milestone for servicing triage.

@simong-hs
Copy link

Recently upgraded Blazor WASM app from .NET 6 to .NET 8, and my Published app throws this exception, in relation to Tuple serialization. Please consider a fix for this in .NET 8.

Implemented following in project file to workaround this temporarily:
<_ExtraTrimmerArgs>--keep-metadata parametername</_ExtraTrimmerArgs>

@lewing
Copy link
Member

lewing commented Feb 5, 2025

@maraf please verify we don't need to do more but I think dotnet/runtime#112216 should get most of this?

@guardrex
Copy link
Contributor

@lewing @maraf ... @pavelsavara and I were just working on a doc section related to the file descriptor approach with a .NET 9 BWA (per-component) project. It's breaking 💥. The test project is at ...

https://github.com/guardrex/BlazorTrimmerTesting

... and when the component is hit, the ...

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair2[System.String,System.String]
System.NotSupportedException: ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair2[System.String,System.String]

... error is thrown.

The docs PR will keep the guidance commented out until it's resolved in the framework. Until then, we'll just have the [DynamicDependency] attribute approach and the custom type approach.

dotnet/AspNetCore.Docs#34734

@pmdot
Copy link

pmdot commented Feb 21, 2025

Here i am too 🙋‍♂️, i've got crashed into that after an upgrade from .net 5 to dotnet 8 😁 workaround will be applied for sure.

@guardrex
Copy link
Contributor

UPDATE on documentation:

Pavel and I worked out that the file descriptor approach is going to need to wait for coverage until at least the release of .NET 10. For now, our current guidance on this scenario is at ...

https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/configure-trimmer?view=aspnetcore-9.0#failure-to-preserve-types-used-by-a-published-app

If the file descriptor approach lights up at .NET 10, we're going to activate that coverage in the article for >=10.0 and remove the last section on using custom types, saying that you can use a custom type but that we don't recommend it.

Currently, the best approach is the dynamic dependency approach. For a KeyValuePair, which is the article's example ...

At the top of the component definition file ...

@using System.Diagnostics.CodeAnalysis

In the @code block ...

[DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(KeyValuePair<string, string>))]
private List<KeyValuePair<string, string>> items = [];

@mguinness
Copy link

That's good documentation Luke. Would it be possible to include that link in the exception message string resource in a similar fashion that's done for the SpecialNumberValuesNotSupported exception as it will be more discoverable by users.

<data name="ConstructorContainsNullParameterNames" xml:space="preserve">
  <value>
    The deserialization constructor for type '{0}' contains parameters with null names. 
    This might happen because the parameter names have been trimmed by ILLink. 
    Consider using the source generated serializer instead 
    (see https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/configure-trimmer#failure-to-preserve-types-used-by-a-published-app).
  </value>
</data>

@guardrex
Copy link
Contributor

@mguinness ... Thanks. That's up the product unit engineers here. I only control the article side of things. We don't want silly green dinosaurs 🦖 mess'in about in the framework code! 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components feature-trimming triaged
Projects
None yet
Development

No branches or pull requests