-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Json serializer code generator doesn't support internal constructors #77016
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsDescriptionIf I have a public class that I want to be able to deserialize, but I don't want that class publicly constructable, I can no longer deserialize it, even though the generated deserializer code has access to the internal constructor. Reproduction StepsIn a console app, add the following code: using System.Text.Json;
using System.Text.Json.Serialization;
string json = "{\"name\":\"Hello World\"}";
var obj = JsonSerializer.Deserialize(json, MyDataModelSerializationContext.Default.MyDataModel);
[JsonSerializable(typeof(MyDataModel))]
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
internal partial class MyDataModelSerializationContext : JsonSerializerContext
{
}
public class MyDataModel
{
// [JsonConstructor] Won't make a difference
internal MyDataModel() { }
public string? Name { get; set; }
} Expected behaviorObject deserializes. Actual behaviorException thrown on deserialize:
Looking at the generated code, you'll note the Regression?No response Known WorkaroundsNot really. If I make the entire class internal (and make the constructor public albeit it is effectively internal now), it works again. However I do want my class to be publicly accessible Configuration.net 6.0.401 Other informationNo response
|
Triage: this can be considered for .NET 8.0. |
FWIW this is by design and consistent with the behavior of the reflection-based serializer. A notable exception is internal getter/setter support via the |
I'm literally porting from the reflection based DataContractSerializer and it works just fine with these internal classes and properties. If we don't have parity I find it hard for us to move and start supporting full trimming in our assemblies. Perhaps there could at least be a setting on |
Is making the constructors public an option? |
No :( |
EF Core is running into similar set of issues with source-generating equivalent of private reflection. Once you start looking at this, we should talk about the possible solutions. |
What might be a way to offer a source-generating equivalent of private reflection? I suppose it might be possible to generate member accessor stubs inside the type declaration itself provided it lives in the same project, but is there any other way you have in mind? |
One extreme is to make JIT pattern-match reflection calls with constant inputs and replace them with direct invocations. For example, if you wrote Other extreme is to emit IL (either via an extra IL .dll or via IL rewriting). It is possible to suppress visibility checks in IL today using So the idea is that we may be able to come up with something viable (e.g. new runtime API) between these two extremes. |
Closing in favor of the more general user story tracked in #87431 |
Description
If I have a public class that I want to be able to deserialize, but I don't want that class publicly constructable, I can no longer deserialize it, even though the generated deserializer code has access to the internal constructor.
This issue prevents moving from
DataContractJsonSerializer
to S.T.J.Reproduction Steps
In a console app, add the following code:
Expected behavior
Object deserializes.
Actual behavior
Exception thrown on deserialize:
Looking at the generated code, you'll note the
ObjectCreator
is null.Compare that to when the constructor is declared public:
Related
A similar issue is hit with a data model like this:
In this case for this internal class, a setter isn't generated for the Name property and during serialization the value is never defined. Granted in this case there's no need to mark it internal since the entire class is already internal - however even if the class is public, I can't restrict the setter from public abuse and only allow the deserializer to set it.
Regression?
No response
Known Workarounds
Not really. If I make the entire class internal (and make the constructor public albeit it is effectively internal now), it works again. However I do want my class to be publicly accessible
Configuration
.net 6.0.401
Other information
No response
The text was updated successfully, but these errors were encountered: