GettingStarted
GettingStarted

Reputation: 7615

JSON Deserialization issue with Ziptastic

public class ZiptasticAPIResponse
{
    [JsonPropertyName("country")]
    public string country { get; set; }
    [JsonPropertyName("state")]
    public string DefaultState { get; set; }
    [JsonPropertyName("city")]
    public string DefaultCity { get; set; }
    [JsonPropertyName("citiesList")]
    public List<CitiesList> CitiesList { get; set; }
}

var url = _alternateURL + zip;
using (var request = new HttpRequestMessage(new HttpMethod("GET"), url))
{
    var response = await httpClient.SendAsync(request);
    Console.WriteLine("--------------------------");
    var content = await response.Content.ReadAsStringAsync();
    var ziptasticResponse = JsonConvert.DeserializeObject<ZiptasticAPIResponse>(content);                   
    ziptasticResponse.CitiesList = new List<CitiesList>()
    {
        new CitiesList()
        {
            State=ziptasticResponse.DefaultCity,City=ziptasticResponse.DefaultCity
        }
    };

    return ziptasticResponse.CitiesList;

I am getting null for DefaultCity and DefaultState but my country is 'US'

when I enter the url in my browser, I get the entire city, state

 https://ziptasticapi.com/90210

What am I missing here?

Upvotes: 0

Views: 56

Answers (1)

dbc
dbc

Reputation: 116980

Your problem is caused by the fact that you are mixing attributes and methods from different serializers. The attribute JsonPropertyName is from System.Text.Json but you are using JsonConvert.DeserializeObject<T>() from Json.NET to deserialize your JSON string. You need to use attributes and methods from the same serializer consistently.

If you want to deserialize using Json.NET, annotate your model with Newtonsoft.Json.JsonPropertyAttribute instead of System.Text.Json.Serialization.JsonPropertyName:

public class ZiptasticAPIResponse
{
    [Newtonsoft.Json.JsonProperty("country")]
    public string country { get; set; }
    [Newtonsoft.Json.JsonProperty("state")]
    public string DefaultState { get; set; }
    [Newtonsoft.Json.JsonProperty("city")]
    public string DefaultCity { get; set; }
    [Newtonsoft.Json.JsonProperty("citiesList")]
    public List<CitiesList> CitiesList { get; set; }
}

And the later

var ziptasticResponse = JsonConvert.DeserializeObject<ZiptasticAPIResponse>(content);                   

If you would prefer to use System.Text.Json in .NET 5.0 you may use HttpClientJsonExtensions.GetFromJsonAsync and leave ZiptasticAPIResponse unchanged:

var url = _alternateURL + zip;
try
{
    var ziptasticResponse = await httpClient.GetFromJsonAsync<ZiptasticAPIResponse>(url);
    return ziptasticResponse;
}
catch (HttpRequestException ex) // Request failed.
{
    // Check status code
    var statusCode = ex.StatusCode;
    Console.WriteLine(statusCode);
}
catch (JsonException) // Malformed JSON
{
    Console.WriteLine("Invalid JSON.");
}
catch (NotSupportedException)
{
    //https://learn.microsoft.com/en-us/aspnet/core/blazor/call-web-api?view=aspnetcore-5.0#handle-errors
    Console.WriteLine("The content type is not application/json.");
}
// handle other exceptions or let them be handled at some higher level.

No matter which you choose, you might want to avoid mixing using Newtonsoft.Json.* and using System.Text.Json.* using statements in any given file. It's easy to make this mistake as the Newtonsoft and System.Text.Json attributes have very similar, and sometimes identical, names.

Demo fiddle for System.Text.Json here.

Upvotes: 1

Related Questions