1

I receive a response from an API and need to convert it to a list of objects in my Xamarin.Forms app. The object that I am deserializing the string into is:

public class ReturnedImg
{
    public string Type { get; set; }
    public string Data { get; set; }
    public double MinX { get; set; }
    public double MaxX { get; set; }
    public double MinY { get; set; }
    public double MaxY { get; set; }
    public ReturnedImg(string typ, string outp, string ymax, string ymin, string xmax, string xmin)
    {
        Type = typ;
        Data = outp;
        MinX = Convert.ToDouble(xmin);
        MaxX = Convert.ToDouble(xmax);
        MinY = Convert.ToDouble(ymin);
        MaxY = Convert.ToDouble(ymax);
    }
}

The code I attempt to use to deserialize the string into a List<ReturnedImg> object is:

List<ReturnedImg> returnedImgs = JsonConvert.DeserializeObject<List<ReturnedImg>>(response);

where response is the returned string. I also tried this:

ReturnedImg[] returnedImgs1 = JsonConvert.DeserializeObject<ReturnedImg[]>(response);

which also didn't work.

Somehow, my API response gets double escaped somewhere between the API and the client.

The string I receive from the API is:

"\"[{\\\"typ\\\": \\\"barcode\\\", \\\"outp\\\": \\\"0882658000546\\\", \\\"ymax\\\": \\\"0.8211805555555556\\\", \\\"ymin\\\": \\\"0.7199900793650794\\\", \\\"xmax\\\": \\\"0.8296957671957672\\\", \\\"xmin\\\": \\\"0.3419312169312169\\\"}, {\\\"typ\\\": \\\"barcode\\\", \\\"outp\\\": \\\"A-0020-Z\\\", \\\"ymax\\\": \\\"0.39360119047619047\\\", \\\"ymin\\\": \\\"0.3881448412698413\\\", \\\"xmax\\\": \\\"0.7027116402116402\\\", \\\"xmin\\\": \\\"0.2919973544973545\\\"}, {\\\"typ\\\": \\\"barcode\\\", \\\"outp\\\": \\\"A-0010-Z\\\", \\\"ymax\\\": \\\"0.2881944444444444\\\", \\\"ymin\\\": \\\"0.20833333333333334\\\", \\\"xmax\\\": \\\"0.6924603174603174\\\", \\\"xmin\\\": \\\"0.2959656084656085\\\"}]\""

When I tested with the string below it did serialize correctly.

"[{\"typ\": \"barcode\", \"outp\": \"0882658000546\", \"ymax\": \"0.8343253968253969\", \"ymin\": \"0.8234126984126984\", \"xmax\": \"0.7235449735449735\", \"xmin\": \"0.22023809523809523\"}, {\"typ\": \"barcode\", \"outp\": \"A-0020-Z\", \"ymax\": \"0.48313492063492064\", \"ymin\": \"0.3916170634920635\", \"xmax\": \"0.6084656084656085\", \"xmin\": \"0.17427248677248677\"}, {\"typ\": \"barcode\", \"outp\": \"A-0010-Z\", \"ymax\": \"0.2934027777777778\", \"ymin\": \"0.21329365079365079\", \"xmax\": \"0.5949074074074074\", \"xmin\": \"0.18882275132275134\"}]"

The error message I'm getting is:

Newtonsoft.Json.JsonSerializationException: 'Error converting value "[{"typ": "barcode", "outp": "0882658000546", "ymax": "0.8343253968253969", "ymin": "0.8234126984126984", "xmax": "0.7235449735449735", "xmin": "0.22023809523809523"}, {"typ": "barcode", "outp": "A-0020-Z", "ymax": "0.48313492063492064", "ymin": "0.3916170634920635", "xmax": "0.6084656084656085", "xmin": "0.17427248677248677"}, {"typ": "barcode", "outp": "A-0010-Z", "ymax": "0.2934027777777778", "ymin": "0.21329365079365079", "xmax": "0.5949074074074074", "xmin": "0.18882275132275134"}]" to type 'System.Collections.Generic.List`1[Label_Reader.ReturnedImg]'. Path '', line 1, position 373.'

The only difference with the other code is that the type given in the error message was Label_Reader.ReturnedImg[].

When I looked at the CloudWatch logs for the API, however, the method response was not double escaped; here is one of the log statements:

(2722b67c-8991-40d8-a7d5-e6f9dfc4477d) Method response body after transformations: "[{\"typ\": \"barcode\", \"outp\": \"0882658000546\", \"ymax\": \"0.763640873015873\", \"ymin\": \"0.5935019841269841\", \"xmax\": \"0.8412698412698413\", \"xmin\": \"0.28075396825396826\"}, {\"typ\": \"barcode\", \"outp\": \"A-0020-Z\", \"ymax\": \"0.4419642857142857\", \"ymin\": \"0.3506944444444444\", \"xmax\": \"0.728505291005291\", \"xmin\": \"0.25892857142857145\"}, {\"typ\": \"barcode\", \"outp\": \"A-0010-Z\", \"ymax\": \"0.2544642857142857\", \"ymin\": \"0.18725198412698413\", \"xmax\": \"0.7106481481481481\", \"xmin\": \"0.29133597883597884\"}]"
Owen Burns
  • 120
  • 10
  • 1
    I tested your code with the provided input and it worked. – Magnetron Aug 18 '21 at 15:15
  • This was exactly the answer I very much hoped I wouldn't receive haha... – Owen Burns Aug 18 '21 at 15:16
  • Check if your response is equal to the input you provided. Also, check for 0 width or invisible characters. https://dotnetfiddle.net/aXDo8k – Magnetron Aug 18 '21 at 15:19
  • I put a breakpoint before that line to check that the response that is to be deserialized is correct and I've seen no errors with it. However, the has some extra backslash characters when I look at it in the locals section of VS. In order to have the text \" in the string it has \\\" there. Could that be the issue? – Owen Burns Aug 18 '21 at 15:27
  • It could be indeed – Laurent Aug 18 '21 at 15:35
  • 2
    it's not entirely clear from your question, but if the JSON string shown in your question is the raw response, rather than a c# string literal, it looks like the JSON was double-serialized. If so, you need to deserialize it twice as shown in [Parsing this kind of json stringified string `“{\”value\“:[\”18\“]}”`](https://stackoverflow.com/q/41454690/3744182). (Or, fix the server to not serialize JSON twice.) – dbc Aug 18 '21 at 15:52
  • Incidentally, Json.NET (and also System.Text.Json) will probably work better if your parameterized constructor arguments have the same name as your properties, because the serializer automatically matches JSON properties to constructor arguments by name. See: [JSON.net: how to deserialize without using the default constructor?](https://stackoverflow.com/q/23017716/3744182) or [How does JSON deserialization in C# work](https://stackoverflow.com/q/41870132/3744182). – dbc Aug 18 '21 at 15:56
  • I updated my question with everything I've just figured out about it being double serialized. Do you know why it might have gotten double serialized? Since it isn't in the API logs and is as soon as it reaches the client I'm not sure what could have messed it up in between – Owen Burns Aug 18 '21 at 16:00
  • @OwenBurns - we have no way of knowing why the server is double-serializing the JSON without seeing the code. In [tag:asp.net-web-api] this typically happens when you have some method that returns a JSON string rather than the object that was serialized as JSON. See e.g. [JSON.NET Parser *seems* to be double serializing my objects](https://stackoverflow.com/q/25559179/3744182) or [Strings sent through Web API's gets wrapped in quotes](https://stackoverflow.com/q/33681978/3744182). – dbc Aug 18 '21 at 16:02
  • *When I looked at the CloudWatch logs for the API, however, the method response was not double escaped* - actually it looks like it was. You may be confusing c# string literal escaping which is evaluated at compile time with JSON string escaping which occurs in runtime. They look the same but they are completely different. It's unlikely the log file would contain c# escaped string literals. I don't know how CloudWatch logs are formatted so I can't say for sure though, maybe the logging mechanism is escaping or formatting the content somehow. – dbc Aug 18 '21 at 16:04
  • 1
    Alright that was it I used json.dumps() twice in the backend. Thank you for the help! – Owen Burns Aug 18 '21 at 16:17

1 Answers1

0

dbc was correct in saying that my Json string was double escaped because of something in the backend. My API called a lambda function that called another lambda function, and I had used json.dumps() on both return statements. Removing the json.dumps from the return statement of the child function solved the issue and prevented the double escaping from occurring.

Owen Burns
  • 120
  • 10