Open SicJG opened 1 year ago
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis See info in area-owners.md if you want to be subscribed.
Author: | SicJG |
---|---|
Assignees: | - |
Labels: | `area-System.Text.Json` |
Milestone: | - |
Only scenario 1
is not working currently. I think this is caused by artificial check I added which prevents from using read-only properties with [Required]
- seems I missed the case with parametrized ctor + read-only property test case. I think the fix is simply adjusting that check + tests.
@SicJG thanks for the report on this, I've sent a PR with a fix. Once it's merged you should be able to consume nightly NuGet package with a fix some time after that. I'll check if it qualifies for servicing fix for 7.0 but no promises on that.
I don't believe this meets the bar for a 7.0 fix. JsonRequiredAttribute
can only be applied to properties and has no effect on constructor parameters, even though the serializer will -by convention- associate constructor parameters to property getters when deriving constructor parameter metadata. The current behavior is consistent with how the C# compiler treats the required
keyword in getter-only properties, for example the following does not compile:
public class MyPoco
{
public MyPoco(int value) => Value = value;
public required int Value { get; }
}
That being said, we should make sure that JsonRequiredAttribute
can be applied consistently to constructor parameters in the future -- however this should probably be implemented in the context of https://github.com/dotnet/runtime/issues/71944 as there is a lot of nuance to be accounted for.
Unfortunately, this is a blocker for us to use the JsonRequiredAttribute
feature on .NET 7. Pity.
@MartyIX the isolated fix is in the PR https://github.com/dotnet/runtime/pull/78152.
There is also workaround which I didn't mention yet:
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
JsonSerializerOptions options = new()
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
{
Modifiers = { JsonRequiredWithPropertiesWithoutSetter }
}
};
MyPoco obj = JsonSerializer.Deserialize<MyPoco>("""{"Value": 123}""", options);
Console.WriteLine(obj.Value);
void JsonRequiredWithPropertiesWithoutSetter(JsonTypeInfo typeInfo)
{
if (typeInfo.Kind != JsonTypeInfoKind.Object)
return;
foreach (var property in typeInfo.Properties)
{
if (property.IsRequired && property.Set == null)
{
// this will never be called for parameterized constructors
property.Set = (obj, val) => throw new JsonException("Required property doesn't have setter");
}
}
}
public class MyPoco
{
public MyPoco(int value) => Value = value;
[JsonRequired]
public int Value { get; }
}
Moving to 9.0 per https://github.com/dotnet/runtime/pull/78152#issuecomment-1638468540
Might be considered as closed due to implementation of JsonSerializerOptions.RespectRequiredConstructorParameters as well as JsonSerializerOptions.RespectNullableAnnotations Thank you for this functionality!
It seems we might still want to make this work if the flag hasn't been enabled though. Let's leave this open for now.
Description
Reproduction Steps
Expected behavior
Local
Reproduction test returns instance of RequiredAttributeCtor type populated with data from input
Global
All of the required property initialization variations are supported
Actual behavior
Running reproduction test throws
Regression?
No response
Known Workarounds
No response
Configuration
SDK version: 7.0.100 OS: Windows 10 1909 Arch: x64
Other information
It seems like implementation of required keyword support in https://github.com/dotnet/runtime/pull/72937 was made in way that makes JsonRequiredAttribute usage absolutely simular to new "required" keyword usage, missing the fact that validating absence of input json property using attribute might be used in other scenarios.