Search code examples
c#restsharpjson-deserialization

Error deserializing a json collection from a rest API


I'm trying to use RestSharp to get a List from an API and I'm getting this error:

System.Text.Json.JsonException: 'The JSON value could not be converted to System.Collections.Generic.List`1[VP_Sysmac.ConsoleTest.OperariModel]. Path: $ | LineNumber: 0 |

I can access the same API using Postman and I'm getting the payload I posted below and Status 200 OK.

If I set up a breakpoint this is the internal value of the jsonString:

"\"[\\r\\n  {\\r\\n    \\\"IdOperari\\\": 0,\\r\\n    \\\"Operari\\\": \\\"Varis\\\",\\r\\n    \\\"TagRfid\\\": \\\"AAA\\\"\\r\\n  },\\r\\n  {\\r\\n    \\\"IdOperari\\\": 38,\\r\\n    \\\"Operari\\\": \\\"Pujol Costa, Josep\\\",\\r\\n    \\\"TagRfid\\\": \\\"AAA\\\"\\r\\n  },\\r\\n  {\\r\\n    \\\"IdOperari\\\": 41,\\r\\n    \\\"Operari\\\": \\\"Barea González, Antonio\\\",\\r\\n    \\\"TagRfid\\\": \\\"AAA\\\"\\r\\n  },\\r\\n  {\\r\\n    \\\"IdOperari\\\": 42,\\r\\n    \\\"Operari\\\": \\\"Basora Grau, Àngel\\\",\\r\\n    \\\"TagRfid\\\": \\\"AAA\\\"\\r\\n  },\\r\\n  {\\r\\n    \\\"IdOperari\\\": 44,\\r\\n    \\\"Operari\\\": \\\"Roy Torras, Jordi\\\",\\r\\n    \\\"TagRfid\\\": \\\"AAA\\\"\\r\\n  }\\r\\n]\""

If I use the JSON visualizer I get exactly the same result than using Postman. If I use a string variable with the json value I can deserialize it without any problem.

The model

internal class OperariModel
{
    public int IdOperari { get; set; }
    public string? Operari { get; set; }
    public string? TagRfid { get; set; }
}

Accessing rest API

static async Task Main(string[] args)
{
    string baseUrl = "http://myserver/apisysmac/api";
    var options = new RestClientOptions(baseUrl)
    {
        RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
    };

    RestClient client = new RestClient(options);

    var request = new RestRequest($"{baseUrl}/Operaris");

    var response = await client.GetAsync(request);

    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        string json = response.Content.ToString();
        var operaris = JsonSerializer.Deserialize<List<OperariModel>>(json);
    }
}

Payload received using Postman

[
  {
    "IdOperari": 0,
    "Operari": "Varis",
    "TagRfid": "AAA"
  },
  {
    "IdOperari": 38,
    "Operari": "Pujol Costa, Josep",
    "TagRfid": "AAA"
  },
  {
    "IdOperari": 41,
    "Operari": "Barea González, Antonio",
    "TagRfid": "AAA"
  },
  {
    "IdOperari": 42,
    "Operari": "Basora Grau, Àngel",
    "TagRfid": "AAA"
  },
  {
    "IdOperari": 44,
    "Operari": "Roy Torras, Jordi",
    "TagRfid": "AAA"
  }
]

Solution

  • System.Text.Json is much more stringent on how it handles any atypical text that doesn't fit the JSON spec, which includes carriage returns and escape characters.

    Before deserializing, you need to sanitize your input string. Regex.Unescape will do this for you, although you will need to manually strip your leading and trailing escaping \ characters.

    string json = response.Content.ToString();
    json = json.Remove(0, 1);
    json = json.Remove(json.Length - 1, 1);
    var sanitizedJsonString = Regex.Unescape(json);
    var operaris = JsonSerializer.Deserialize<List<OperariModel>>(sanitizedJsonString);
    

    Ideally however, you should never have to project to a string and then sanitize it.

    RestSharp uses System.Text.Json as its default serializer and will handle deserialization for you if you use the appropriate methods.

    var request = new RestRequest($"{baseUrl}/Operaris");
    var response = await client.GetAsync<List<OperariModel>>(request);