Search code examples
c#json.netfirebase-security

Deserializing Firebase User Data response using Newtonsoft.Json library


I am using C# to deserialize a Firebase Auth REST API Get User response using Newtonsoft.Json library. Below is a sample of the JSON output:

{
  "kind": "identitytoolkit#GetAccountInfoResponse",
  "users": [
    {
      "localId": "asdfsdsfs",
      "email": "[email protected]",
      "passwordHash": "asdsdfsdfd",
      "emailVerified": false,
      "passwordUpdatedAt": 1985545511525,
      "providerUserInfo": [
        {
          "providerId": "password",
          "federatedId": "[email protected]",
          "email": "[email protected]",
          "rawId": "[email protected]"
        }
      ],
      "validSince": "16496321050",
      "lastLoginAt": "16874526844",
      "createdAt": "164123654725",
      "lastRefreshAt": "2022-03-19T16:53:56.844Z"
    }
  ]
}

I used this code to attempt to deserialize it:

Dictionary<string, List<Dictionary<string, object>>> responseText = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, List<Dictionary<string, object>>>>(request.downloadHandler.text);

However, I get this error:

ArgumentException: Could not cast or convert from System.String to System.Collections.Generic.List1[System.Collections.Generic.Dictionary2[System.String,System.Object]]. Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable (System.Object value, System.Type initialType, System.Type targetType) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast (System.Object initialValue, System.Globalization.CultureInfo culture, System.Type targetType) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType (Newtonsoft.Json.JsonReader reader, System.Object value, System.Globalization.CultureInfo culture, Newtonsoft.Json.Serialization.JsonContract contract, System.Type targetType) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Rethrow as JsonSerializationException: Error converting value "identitytoolkit#GetAccountInfoResponse" to type 'System.Collections.Generic.List1[System.Collections.Generic.Dictionary2[System.String,System.Object]]'. Path 'kind', line 2, position 50. Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType (Newtonsoft.Json.JsonReader reader, System.Object value, System.Globalization.CultureInfo culture, Newtonsoft.Json.Serialization.JsonContract contract, System.Type targetType) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary (System.Collections.IDictionary dictionary, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonDictionaryContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, System.String id) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.JsonSerializer.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.JsonConvert.DeserializeObject (System.String value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) (at <7ca8898b690a4181a32a9cf767cedb1e>:0) Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value) (at <7ca8898b690a4181a32a9cf767cedb1e>:0)


Solution

  • The error is telling you that it can't convert a string into a List<Dictionary<string, object>> - the json values don't represent List<Dictionary<,>>.

    You could deserialize the json to Dictionary<string, object> or dynamic:

    Dictionary<string, object> responseText = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
    // or
    dynamic responseText = JsonConvert.DeserializeObject<dynamic>(json);
    

    However, unless the json is dynamic and changing constantly, a better option is to deserialize to a concrete class or classes which model the json. There are apps online to help you convert the json to C# classes. You could use json2csharp.com, app.quicktype.io, or VisualStudio Paste JSON as Classes.

    I used json2csharp, which output the following (including how to deserialize the json):

    Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
    
    public class ProviderUserInfo
    {
        public string providerId { get; set; }
        public string federatedId { get; set; }
        public string email { get; set; }
        public string rawId { get; set; }
    }
    
    public class User
    {
        public string localId { get; set; }
        public string email { get; set; }
        public string passwordHash { get; set; }
        public bool emailVerified { get; set; }
        public long passwordUpdatedAt { get; set; }
        public List<ProviderUserInfo> providerUserInfo { get; set; }
        public string validSince { get; set; }
        public string lastLoginAt { get; set; }
        public string createdAt { get; set; }
        public DateTime lastRefreshAt { get; set; }
    }
    
    public class Root
    {
        public string kind { get; set; }
        public List<User> users { get; set; }
    }
    

    Online example of all 3 methods