The output type for a dynamic property without changing the class?

I have a bunch of domain objects that I serialize, send to other applications, and then deserialize with Json.Net. These objects may have properties.

  • Defined as an abstract base class with multiple derived classes.
  • Dynamic properties

I used TypeNameHandling.Autoone that adds a property $typeto types that are different from the declared type. However, this parameter has an undesirable side effect on my dynamic properties, namely that their types are also declared.

In the example below model, this is a dynamic property defined as public dynamic Model { get; set; }in my C # code.

"model":{"$type":"<>f__AnonymousType0`3[[System.String, mscorlib],[System.String, mscorlib],[System.String, mscorlib]], ExampleAssembly","link":"http://www.google.com","name":"John"}

When trying to deserialize this line in another assembly, Json.Net cannot (of course) find it ExampleAssembly. Using a property TypeNameHandling.Nonegives the following serialization of properties

"model": {"link":"http://www.google.com","name":"John"}

What you can successfully deserialize to dynamic. However, this disrupts the deserialization of derived types.

Any ideas on how to get this to work without implementing custom IContractResolverand possibly other custom code?

I don’t own domain objects, so I can’t decorate them or their properties with attributes or let them implement interfaces, etc. What I'm looking for is some kind of setup in a serializer that doesn't use types for dynamics.

IMHO, this must be configured through the settings somehow, I just did not find it.

+2
1

Json.Net . ( ) [JsonProperty(TypeNameHandling = TypeNameHandling.None)], ( Json.Net) , . , , Json.Net , DefaultContractResolver CamelCasePropertyNamesContractResolver.

, :

using System;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public class OmitTypeNamesOnDynamicsResolver : DefaultContractResolver
{
    public static readonly OmitTypeNamesOnDynamicsResolver Instance = new OmitTypeNamesOnDynamicsResolver();

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);
        if (member.GetCustomAttribute<System.Runtime.CompilerServices.DynamicAttribute>() != null)
        {
            prop.TypeNameHandling = TypeNameHandling.None;
        }
        return prop;
    }
}

JsonSerializerSettings, .

JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance
};

string json = JsonConvert.SerializeObject(foo, settings);

, :

public class Program
{
    public static void Main(string[] args)
    {
        Foo foo = new Foo
        {
            Model = new { link = "http://www.google.com", name = "John" },
            Widget1 = new Doodad { Name = "Sprocket", Size = 10 },
            Widget2 = new Thingy { Name = "Coil", Strength = 5 }
        };

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Auto,
            ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance,
            Formatting = Formatting.Indented
        };

        string json = JsonConvert.SerializeObject(foo, settings);
        Console.WriteLine(json);
        Console.WriteLine();

        Foo foo2 = JsonConvert.DeserializeObject<Foo>(json, settings);
        Console.WriteLine(foo2.Model.link);
        Console.WriteLine(foo2.Model.name);
        Console.WriteLine(foo2.Widget1.Name + " (" + foo2.Widget1.GetType().Name + ")");
        Console.WriteLine(foo2.Widget2.Name + " (" + foo2.Widget2.GetType().Name + ")");
    }
}

public class Foo
{
    public dynamic Model { get; set; }
    public AbstractWidget Widget1 { get; set; }
    public AbstractWidget Widget2 { get; set; }
}

public class AbstractWidget
{
    public string Name { get; set; }
}

public class Thingy : AbstractWidget
{
    public int Strength { get; set; }
}

public class Doodad : AbstractWidget
{
    public int Size { get; set; }
}

:

{
  "Model": {
    "link": "http://www.google.com",
    "name": "John"
  },
  "Widget1": {
    "$type": "Doodad, JsonTest",
    "Size": 10,
    "Name": "Sprocket"
  },
  "Widget2": {
    "$type": "Thingy, JsonTest",
    "Strength": 5,
    "Name": "Coil"
  }
}

http://www.google.com
John
Sprocket (Doodad)
Coil (Thingy)
+3

Source: https://habr.com/ru/post/1691900/


All Articles