Open smfields opened 1 year ago
What you see could be the effect of trimming applied to the Blazor webassembly project (note the empty member name in the exception message, which could be an indication of this).
Therefore, first verify if trimming is the actual cause of your problem by disabling trimming for your Blazor webassembly project and check whether the problem still occurs without trimming.
If you have identified trimming to be the cause of the problem, evaluate whether you can switch to System.Text.Json, a json serializer using code generators. Because Newtonsoft.Json/Json.NET relies heavily on reflection, and reflection-based code often does not play very well with trimming without special care.
Quote from https://learn.microsoft.com/en-gb/dotnet/core/deploying/trimming/prepare-libraries-for-trimming:
Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed.
(Emphasis mine)
If you prefer to use Newtonsoft.Json/Json.NET while still trimming your project, you will have to configure your Blazor web assembly in a manner so that the trimmer does not trim away the types or the respective type members of any possible (data) objects and interfaces that potentially participating deserialization - such as properties, fields and especially constructors that will only be accessed by the Json.NET (de)serializer through reflection. For documentation/guidance, see here: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options
What you see could be the effect of trimming applied to the Blazor webassembly project (note the empty member name in the exception message, which could be an indication of this).
Therefore, first verify if trimming is the actual cause of your problem by disabling trimming for your Blazor webassembly project and check whether the problem still occurs without trimming.
If you have identified trimming to be the cause of the problem, evaluate whether you can switch to System.Text.Json, a json serializer using code generators. Because Newtonsoft.Json/Json.NET relies heavily on reflection, and reflection-based code often does not play very well with trimming without special care.
Quote from https://learn.microsoft.com/en-gb/dotnet/core/deploying/trimming/prepare-libraries-for-trimming:
Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed.
(Emphasis mine)
If you prefer to use Newtonsoft.Json/Json.NET while still trimming your project, you will have to configure your Blazor web assembly in a manner so that the trimmer does not trim away the types or the respective type members of any possible (data) objects and interfaces that potentially participating deserialization - such as properties, fields and especially constructors that will only be accessed by the Json.NET (de)serializer through reflection. For documentation/guidance, see here: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options
Thanks for your quick (and thorough) repsonse. Forgive me if I've misunderstood, I'm not very familiar with the idea of trimming.
I tried disabling trimming in the WebAssembly project by adding <PublishTrimmed>false</PublishTrimmed>
and/or <TrimMode>partial</TrimMode>
to the csproj. The error still reproduced, but I'm not entirely sure if this actually disables trimming or not.
I also tried explicitly turning on trimming for the ConsoleApp to see if I could get it to reproduce the error, but it did not. That being said, it looks like starting in .NET 7 all assemblies have trimming enabled by default. Again, forgive me if I've misunderstood.
I'd really prefer to stick with JSON.NET in this case, so are there any other potential causes for this error? It's unfortunately quite difficult to debug 3rd party libraries in WASM, so I can't easily dig into things myself.
Hmm, looking closer, you are uisng Castle DynamicProxy, which itself uses System.Reflection.Emit, apparently to create proxy types dynamically at runtime. (My suspicion regarding trimming was a false flag. My apologies.)
Considering this and your stacktrace that indicates Json.NET inspecting some ConstructorInfo for the dynamically generated proxy type that then leads it to detect a constructor parameter with no/empty name, i took a look at the respective method in Json.NET. (Side note: look at the code comment inside that method there, lol):
Note how the constructor parameter names are tested against null
. But they are not tested against an empty string. I don't know if Castle can create constructor parameters for a proxy with a name that is not null but an empty string under certain circumstances, but it almost looks like that. And if that were to be the case, then Json.NET is not yet prepared for this (and therefore this being a bug/limitation).
Unfortunately, i am unable to set up and test your webassembly project (nor do i have much technical experience with wasm anyways), so i can't check for myself. If you want to, perhaps try reflecting over the type of the generated proxy instance when running as part of your webassembly project, and see/log if the parameter names of the constructor(s) of this type are either null, an empty string or some other name consisting only of some weird Unicode zero-width control/format characters. Not that this will help you fixing or working around the issue, but it could help confiriming what the actual constructor parameter names of the proxy object are when running in the webassembly...
I setup the test you recommended and as you predicated it looks like the constructor parameter names are being set to null
in the ConsoleApp, but an empty string in the WebAssemblyApp.
(Sorry, i deleted my last comment. I misread your comment, falsely reading that the ctor parameter names are null in the WebAssemblyApp. Ooops...)
an empty string in the WebAssemblyApp.
Alright. That is then an issue with Json.NET library...
Is there any workaround or a resolution for this issue. Have been facing this issue with a weird usecase, My API deserialization works with Debug configuration but throws error in Release configuration
Newtonsoft.Json.JsonSerializationException: A member with the name '' already exists on 'System.Tuple2[System.String,System.String]'. Use the JsonPropertyAttribute to specify another name
@RagavanPV Did you get any solution for it? I am also facing similar issue...
Source/destination types
Source/destination JSON
CustomCreationConverter
Expected behavior
The proxy converter should create a new proxy type that is populated during deserialization.
Actual behavior
Deserialization works properly in a regular .NET application, such as a console app, but fails when running in WebAssembly. In WebAssembly, the following error is produced:
Steps to reproduce
Reproduction Repo: https://github.com/smfields/NewtonsoftIssueRepro