Search code examples
c#jsondynamicdeserializationambiguous

ambiguity between a string and a dynamic object


        string code = "ru";
        string searchUrl = $"{Endpoint}getLangs?key={ApiKey}&ui=en";
        string json;
        using (var client = new WebClient())
        {
            json = client.DownloadString(searchUrl);
        }

        var dataObject = JsonConvert.DeserializeObject<dynamic>(json);
        return dataObject.langs.code;

In this snippet here searchUrl is a string and holds the URL of the API I am using. Now the last line return dataObject.langs.code; returns null as there is no such entry in the json which is in dataObject(a dynamic object). But return dataObject.langs.ru; returns a proper string that I was expecting.

This is happening because in return dataObject.langs.code; code is a dynamic member of dataObject and not the string code i declared above. How can I use that code that I declared and not the dynamic code it thinks there exists in dataObject since it is dynamic.


Solution

  • I wouldn't use dynamic at all. That's typically useful when you know the names you want to use at compile-time. I'd deserialize to a JObject and just use indexers, where you can provide the property name either using something you know at compile-time (like "langs") or something you only know at execution time (like code):

    var dataObject = JObject.Parse(json);
    // Modify this to cast to whatever type you're actually interested in
    return (string) dataObject["langs"][code];
    

    Here's a complete example:

    using System;
    using System.IO;
    using Newtonsoft.Json.Linq;
    
    class Test
    {
        static void Main()
        {
            string json = File.ReadAllText("test.json");
            string code = "ru";
            JObject dataObject = JObject.Parse(json);
            string result = (string) dataObject["langs"][code];
            Console.WriteLine(result);
        }
    }
    

    With test.json containing:

    {
      "langs": {
        "ru": "Russian",
        "en": "English",
        "fr": "French"
      },
      "misc": {
        "foo": "bar"
      }
    }
    

    Output:

    Russian