Search code examples
c#jsonjson.net

Unable to deserialize JSON in C# using the same class at both ends


I'm looking for someone to point out the obvious blunder here.

A .NET Core in C# application makes an HTTP call to another such application. Some processing is performed, and a response is sent thus:

 Response response = new Response(input)
        {
            stuff = processedStuff;
        };
        responseMessage = JsonConvert.SerializeObject(response);
        return new OkObjectResult(responseMessage);

This all looks good and responseMessage contains valid JSON (according to an online JSON checker I found).

At the other end, this is received thus:

Response returned = new Response();
var response = await client.SendAsync(request);
                if (response.IsSuccessStatusCode)
                {
                    var json = await response.Content.ReadAsStringAsync();
                    returned = JsonConvert.DeserializeObject<Response>(json);
                }

This fails with an Error converting value *the JSON string* to "Response" at line 1

Response is the same class file in both applications. What never obvious and apparently invisible mistake am I making here?


Solution

  • The invisible mistake you are making is double-serializing the result. The contract of OkObjectResult is that it will automatically serialize the result object to the negotiated content type (e.g. JSON or XML) and return an OK status. You are serializing the object first and then passing the serialized string to OkObjectResult so it ends up getting serialized twice.

    responseMessage = JsonConvert.SerializeObject(response);   // serialize to JSON
    return new OkObjectResult(responseMessage);                // implicit serialization here
    

    Possible solutions:

    1. Allow the implicit serialization to do its thing (recommended):

      return new OkObjectResult(response);   // implicit serialization of response object
      
    2. Use a ContentResult instead (good if you need special serialization handling):

      responseMessage = JsonConvert.SerializeObject(response);   // serialize to JSON
      return new ContentResult()
      {
          Content = responseMessage,
          ContentType = "application/json",
          StatusCode = 200
      };
      
    3. Deserialize twice on the receiving end (use as a last resort, i.e. you don't control the server):

      var doubleSerializedJson = await response.Content.ReadAsStringAsync();
      var json = JsonConvert.DeserializeObject<string>(doubleSerializedJson);
      returned = JsonConvert.DeserializeObject<Response>(json);