0

I am working on code that processes responses from OpenLibrary. This is a rest service that returns books based on a passed in ISBN. An example URL is this:

https://openlibrary.org/api/books?bibkeys=ISBN:9780596005405&jscmd=data&format=json

{
    ISBN:9780596005405: {
        publishers: [
            {
                name: "O'Reilly"
            }
        ],
        pagination: "xxxii, 854 p. :",
        identifiers: {
        lccn: [
            "2006281089"
        ],
        openlibrary: [
            "OL17924716M"
        ],
        isbn_10: [
            "0596005407"
        ],
        goodreads: [
            "58129"
        ],
        librarything: [
            "187028"
        ],
    },
    .... other properties omitted for brevity
}

I have these objects:

public class OLResult
{
    Publishers Publishers { get; set; }
    // other properties
}

public class Publishers
{
    // properties go here
}

I created C# objects that are identical to what OpenLibrary returns. However, if you look at the response, you'll notice it's a JSON with a root element with a weird key: ISBN: followed by the passed in ISBN number. Newtonsoft.Json does not know how to map this dynamic key to my OLResult object.

I have created a simple converter to manually convert this JSON to the correct object:

public class OpenLibraryResultConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        OLResult result = new OLResult();

        // Perform magic to copy JSON results to result object. 

        return result;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

I have also added an attribute [JsonConverter(typeof(OpenLibraryResultConverter))] to my OLResult class. When I call JsonConvert.DeserializeObject<OLResult>(jsonStringResult);, and use the debugger to check the ReadJson method, I can not seem to find the JSON data of the jsonStringResult parameter I passed in to the converter. Most properties of the parameters passed into the ReadJson method appear null or empty.

My question: how do I successfully read out the JSON string in my new JsonConverter?

yesman
  • 7,165
  • 15
  • 52
  • 117
  • 2
    You didn't post the JSON. Don't force people to copy a big chunk of text from some link and format it just to understand what you're asking or why you had to create a converter – Panagiotis Kanavos Nov 28 '19 at 08:26
  • Ah, good point. I'll update the post. – yesman Nov 28 '19 at 08:28
  • 3
    Use a `Dictionary` for your root object as shown in [How can I parse a JSON string that would cause illegal C# identifiers?](https://stackoverflow.com/a/24536564/3744182) or [Create a strongly typed c# object from json object with ID as the name](https://stackoverflow.com/a/34213724/3744182) In fact I think this is a duplicate, agree? I don't even think you need a converter if you deserialize to a dictionary. – dbc Nov 28 '19 at 08:54
  • @dbc, totaly a duplicate. Even if the title didn't match it's a Dictionary thingy. Let me Flag that for you. If you don't feel like swinging the hammer. And let community do the vote if they agree. – xdtTransform Nov 28 '19 at 09:54
  • @yesman, Dupe are not a bad thing, we are just pointing every arrow to the bigger correct solution. But btw when ask for a Json sample you really past an invalid Json,. Throwing people on the invalid json trail. Let me fix that for you – xdtTransform Nov 28 '19 at 09:56

2 Answers2

1

In case you don't need that dynamic property number: ISBN:XXXXXX you can go with something simple like using partial JSON serialization that you can check out here

carlesgg97
  • 4,184
  • 1
  • 8
  • 24
ErBu
  • 355
  • 2
  • 7
0

It's not clear from the post., but the first part is actually a label, so the overall structure is like this:

{
   "ISBN:9780596005405": {...}
}

Note that the label contains a colon, which makes it more difficult to translate directly into a C# object. But either way, you'll need to either define an object class for that and parse it, or as @Ernestas suggests, skip it.

devb
  • 269
  • 1
  • 8
  • I solved it like this public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jo = JObject.Load(reader); return jo.Properties().Where(jp => jp.Value.Type == JTokenType.Object) .ToDictionary(jp => jp.Name, jp => jp.Value.ToObject()); } – Recep Duman Jul 09 '21 at 23:00