1

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 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your idea. This is a decent workaround knowing the basics of how the JSON.Net works. I am still hoping that someone with a more intimate knowlege of JSON.Net has a more elegant solution.
Yes, from my knowledge this seemed like the most straight forward work around. I imagine it will end up being a custom serializer.
0

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);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.