1
votes

I'm deserializing some JSON from a server which is, for the most part, simple:

{
    "id": "ABC123"
    "number" 1234,
    "configured_perspective": "ComplexPerspective[WithOptions,Encoded]"
}

That "configured_perspective" property, however, is an unfortunate case of the server using a weirdly put-together string when a nested object would have been better.

To ease the suffering of our .NET users, I convert this into a custom class in my object model:

public class Example
{
    public string id { get; set; }
    public int number { get; set; }
    public Perspective configured_perspective { get; set; }
}

// Note, instances of this class are immutable
public class Perspective
{
    public CoreEnum base_perspective { get; }
    public IEnumerable<OptionEnum> options { get; }

    public Perspective(CoreEnum baseArg, IEnumerable<OptionEnum> options) { ... }
    public Perspective(string stringRepresentation) {
        //Parses that gross string to this nice class
    }
    public static implicit operator Perspective(string fromString) =>
        new Perspective(fromString);
    public override string ToString() =>
        base_perspective + '[' + String.Join(",", options) + ']';
}

As you can see, I've put together a custom class Perspective that converts to and from the JSON string, but I can't seem to get Newtonsoft JSON to automatically convert the string to my Perspective class.


I tried getting it to call the string constructor with the [JsonConstructor] attribute, but it just calls the constructor with null, not with the string value present in the JSON.

I was under the impression (based on https://stackoverflow.com/a/34186322/529618) that JSON.NET would use implicit/explicit string conversion operators to convert a simple string in JSON to an instance of the target type when available, but it seems to ignore it, and just returns the error:

Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type Perspective. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'configured_perspective'


I'm trying to avoid resorting to writing a custom JsonConverter for my Example class - I was pretty sure there would be an out-of-the-box way to convert simple string values to a non-string property type, I just haven't found it yet.

2

2 Answers

1
votes

I actually wrote out a custom serializer class before doing reading the last of your article, but I then had an idea.

What if we modified example to not serialize it to Perspective? And we were somewhat lazy about it?

public class Example 
{
    public string id { get; set; }
    public int number { get; set; }
    public string configured_perspective { get; set; }
    private Perspective _configuredPespective;
    [JsonIgnore]
    public Perspective ConfiguredPerspective => _configuredPerspective == null ? new Perspective(configured_persective) : _configuredPerspective;

}

It's not perfect, and we hold onto the string wasting memory, but it might work for you as a work-around.

0
votes

Currently I'm using the following variation on @Jlalonde's suggestion - tweaked such that the user experience doesn't change, taking advantage of the fact that JSON.NET looks for private properties as well.

public class Example
{
    public string id { get; set; }
    public int number { get; set; }
    [JsonIgnore]
    public Perspective configured_perspective { get; set; }
    [DataMember(Name = "configured_perspective")]
    private string configured_perspective_serialized
    {
        get => configured_perspective?.ToString();
        set => configured_perspective = value == null ? null : new Perspective(value);
    }
}