Skip to content
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

System.Text.Json.JsonSerializer.Serialize, when JsonIgnoreAttribute and "required" used together, throw exception #78443

Closed
chsword opened this issue Nov 16, 2022 · 2 comments

Comments

@chsword
Copy link

chsword commented Nov 16, 2022

Description

When JsonIgnoreAttribute and C# required used together, throw exception

    public void TestRequired()
    {
        var model = new TestModel
        {
            Str1 = "a",
            Str2 = "b"
        };
        var json = System.Text.Json.JsonSerializer.Serialize(model);
        Console.WriteLine(json);
    }

    public class TestModel
    {
        [System.Text.Json.Serialization.JsonIgnore]
        public required  string Str1 { get; set; }
        [JsonPropertyName("s_str2")]
        public required string Str2 { get; set; }
    }

Configuration

.NET 7
Windows

Regression?

Other information

System.InvalidOperationException: JsonPropertyInfo 'Str1' defined in type 'LingHuo.SDK.Tests.Tencent.TencentFaceIdH5Test+TestModel' is marked required but does not specify a setter.
    at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndNotDeserializable(JsonPropertyInfo jsonPropertyInfo)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.InitializePropertyCache()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureLocked|143_0()
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
   at 
@mairaw mairaw transferred this issue from dotnet/core Nov 16, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Nov 16, 2022
@ghost
Copy link

ghost commented Nov 16, 2022

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

Description

When JsonIgnoreAttribute and C# required used together, throw exception

    public void TestRequired()
    {
        var model = new TestModel
        {
            Str1 = "a",
            Str2 = "b"
        };
        var json = System.Text.Json.JsonSerializer.Serialize(model);
        Console.WriteLine(json);
    }

    public class TestModel
    {
        [System.Text.Json.Serialization.JsonIgnore]
        public required  string Str1 { get; set; }
        [JsonPropertyName("s_str2")]
        public required string Str2 { get; set; }
    }

Configuration

.NET 7
Windows

Regression?

Other information

System.InvalidOperationException: JsonPropertyInfo 'Str1' defined in type 'LingHuo.SDK.Tests.Tencent.TencentFaceIdH5Test+TestModel' is marked required but does not specify a setter.
    at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndNotDeserializable(JsonPropertyInfo jsonPropertyInfo)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.InitializePropertyCache()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureLocked|143_0()
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
   at 
Author: chsword
Assignees: -
Labels:

area-System.Text.Json

Milestone: -

@krwq
Copy link
Member

krwq commented Nov 23, 2022

This scenario was blocked by design because we won't ever be able to source generate such code (we must provide property when it's required)... You can workaround it by creating contract resolver modifier and removing this property - it will only work with reflection-based serializer though.

Here is a workaround:

using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;

JsonSerializerOptions options = new()
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver()
    {
        Modifiers =
        {
            RemoveIgnoredPropertiesFromContract
        }
    }
};

var model = new TestModel
{
    Str1 = "a",
    Str2 = "b"
};
var json = JsonSerializer.Serialize(model, options);
Console.WriteLine(json);
// {"s_str2":"b"}

static void RemoveIgnoredPropertiesFromContract(JsonTypeInfo typeInfo)
{
    if (typeInfo.Kind != JsonTypeInfoKind.Object)
        return;

    List<JsonPropertyInfo> properties = new();

    foreach (var prop in typeInfo.Properties)
    {
        if (prop.AttributeProvider != null && prop.AttributeProvider.IsDefined(typeof(JsonIgnoreAttribute), inherit: true))
        {
            continue;
        }

        properties.Add(prop);
    }

    typeInfo.Properties.Clear();

    foreach (var property in properties)
    {
        typeInfo.Properties.Add(property);
    }
}

public class TestModel
{
    [JsonIgnore]
    public required string Str1 { get; set; }
    [JsonPropertyName("s_str2")]
    public required string Str2 { get; set; }
}

I'm closing this as by design though.

@krwq krwq closed this as completed Nov 23, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Nov 23, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Dec 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants