0

My Error is that the controller is not able to map the value; I have this situation that explains how to replicate the error:

    public class FooA {
      public string Property1 { set; get; }
      public virtual string Property2 { set; get; }
    }
    
    public class FooB : FooA {
      public new string Property2 { set; get; } 
      public string Property3 { set; get; }
    }

As you know, the property Property2 is common for both classes, thereby when you are using in any controller this action:

    public async task<string> ActionA([FromBody] FooA fooA)
    {
      return string.Empty;
    }


    // The error is thrown in this unwrapping.
    public async task<string> ActionB([FromBody] FooB fooB)
    {
      return string.Empty;
    }

The payload for FooA is of the request is:

    {
      "Property1" : "abc",
      "Property2" : "def"
    }

The payload for FooB is of the request is:

    {
      "Property2" : "abc",
      "Property3" : "def"
    }

This Exception will be thrown:

    System.InvalidOperationException: The JSON property name for 'FooB' collides with another property.
       at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(JsonClassInfo jsonClassInfo, JsonPropertyInfo jsonPropertyInfo)
       at System.Text.Json.JsonClassInfo..ctor(Type type, JsonSerializerOptions options)

I have added Attributes such as [JsonIgnore] but it fails with a payload like the first one.

or :

            services.AddControllers()
                .AddJsonOptions(options =>
                    {
                        options.JsonSerializerOptions.PropertyNamingPolicy = null;
                        options.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
                    });

But it has not possible, my idea is to be SOLID and avoid to change the entire solution. It means Open Extensions (it means that extensions will solve future issues ) Closed to (already implemented) changes.

Do you have a particular setting in the AddJsonOptions to allow that conflicts by inheritences will be autoresolved using the child class always?

Notes 01: Even, when it is added the virtual ans new reserver keyword the controller throws the same exceptions.

Serge
  • 40,935
  • 4
  • 18
  • 45
Fabio Andrés
  • 229
  • 2
  • 11

1 Answers1

1

you have to fix the classes, you have 2 choices

the common one

public class FooA
{
    public string Property1 { set; get; }
    public virtual string Property2 { set; get; }
}

public class FooB : FooA
{
    public override string Property2 { set; get; }
    public string Property3 { set; get; }
}

or if you want to have an access to 2 properties

public class FooA
{
    public string Property1 { set; get; }
    public string Property2 { set; get; }
}

public class FooB : FooA
{
    public new string Property2 { set; get; }
    public string Property3 { set; get; }
}

test

var json = @"{
      ""Property2"" : ""abc"",
      ""Property3"" : ""def""
    }";

var jsonDeserialized=System.Text.Json.JsonSerializer.Deserialize<FooB>(json);

test reslut (in a json format)

{
  "Property2": "abc",
  "Property3": "def",
  "Property1": null
}

but I recommend you to install Newtonsoft.Json serializer just config it in startup

using Newtonsoft.Json.Serialization;

    services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
           options.SerializerSettings.ContractResolver =
              new CamelCasePropertyNamesContractResolver());

or if you use just controllers

    services.AddControllers()
    .AddNewtonsoftJson(options =>
           options.SerializerSettings.ContractResolver =
              new CamelCasePropertyNamesContractResolver());
Serge
  • 40,935
  • 4
  • 18
  • 45
  • Thanks a lot, I have used this solution but the problem was not solved, do you know if a set of nested classes could cause exception in the deserializer? – Fabio Andrés Jan 18 '22 at 23:11
  • 1
    @FabioAndrés since you are using MS serializer, you will always have only problems. Change it to Newtonsoft or post your json that you can not to deserialize. Post the class that you were trying to deserialize into too. – Serge Jan 18 '22 at 23:14
  • In this segment `[FromBody]` It is possible to force the controller Deserialize for using NewtonSoft insteadof Text.Json Serializer? – Fabio Andrés Jan 19 '22 at 11:36
  • @FabioAndrés I updated my answer – Serge Jan 19 '22 at 11:58
  • This solved my Problem. Thanks very much! it was really picky. – Fabio Andrés Jan 19 '22 at 14:02