1

I can't get my dotnet web api (v. 5.0) to read the json response from another API. It insists on 'decorating' the string with \ and removing quotes. I suspect it assumes the returned content is in a certain format and then tries to 'deserialize' the json content into a string.

My API returns this

{
    "result": [
        {
            "CampaignId": 1
        }
    ]
}

According to postman, the returned raw data is {"result":[{"CampaignId":1}]}

Which seems reasonable.

Problem is, responseContent in the following code

var bodyStr = body.ToString();
var client = new HttpClient();
var httpContent = new StringContent(bodyStr, Encoding.UTF8, "application/json");
var response = await client.PostAsync("http://anotherapi/query",httpContent);            
var responseContent = await response.Content.ReadAsStringAsync();

returns

"{\"result\":[{CampaignId:1}]}"

which obviously fails when reading it as json

using (JsonDocument document = JsonDocument.Parse(responseContent)) {}

EDIT: I get the following exception, when calling JsonDocument.Parse(responseContent):

System.Text.Json.JsonReaderException: 'C' is an invalid start of a property name. Expected a '"'. LineNumber: 0 | BytePositionInLine: 12.

because ReadAsStringAsync() seems to remove the quotes around "CampaignId", which makes the json invalid.

EDIT2: This is the returned response from the other API, according to postman: Postman response RAW

This is the response header: Response header

This is the response according to curl:

$ curl --data "@/somedata.txt" -X POST -H "Content-Type: application/json" http://host/query
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 19847  100    30  100 19817     30  19817  0:00:01  0:00:01 --:--:-- 16083{"result":[{"CampaignId":1}]}

I don't see any problems with the response header or content. Everything seems fine with the returned content and "campaignId" includes the quotes.

user1538142
  • 87
  • 1
  • 7
  • How does it fail? Do you get an exception? Or just `null`? – Dai Feb 01 '22 at 07:35
  • 1
    Are you seeing `"{\"result\":[{CampaignId:1}]}"` only in your debugger? If so, then that's normal: the backslashes aren't actually in the string. But we can't help you without more error information. – Dai Feb 01 '22 at 07:36
  • @Dai thanks for helping me out. This is the output of Console.Writeline(responseContent); {"result":[{CampaignId:21}]} Which is missing the quotes. – user1538142 Feb 01 '22 at 08:04
  • Again, that's fine and normal. I see no problems with your code. – Dai Feb 01 '22 at 08:18
  • @Dai problem is that ReadAsStringAsync removes the quotes around CampaignId, which isn't valid json. So when calling JsonDocument.Parse(responseContent), I get the following exception: System.Text.Json.JsonReaderException: 'C' is an invalid start of a property name. Expected a '"'. LineNumber: 0 | BytePositionInLine: 12. – user1538142 Feb 01 '22 at 08:20
  • @dai I have edited my question, so it is a bit more clear. – user1538142 Feb 01 '22 at 08:22
  • Oh, sorry, I misread your comment. I can assure you that `ReadAsStringAsync` is **not** removing any quotes around `CampaignId`. I suspect that instead the service is actually omitting the quotes when rendering the response, possibly because your request is not setting the `Accept` header (e.g. this is bad content-negotiation, and if the request's `Accept` header does not include `application/json` then it renders a browser-safe faux-JSON response instead of true JSON - I don't know if this is what's actually happening, but it's my best-guess. – Dai Feb 01 '22 at 08:22
  • Also, use a tool like Fiddler to intercept and inspect the response to Postman vs. your C# code - that will also definitely help. – Dai Feb 01 '22 at 08:25
  • @Dai thanks for your reply. I have updated the case again, with more information on what I return from the other API. The header + raw content. Do you think it is still worth trying Fiddler, when both postman and curl show the content I expect? If so, I can try it. – user1538142 Feb 01 '22 at 08:35
  • 1
    Yes, you should use Fiddler because we need to see the raw network traffic for `HttpClient`. – Dai Feb 01 '22 at 08:37
  • 1
    @Dai you were right. Analysed the package through wireshark and CampaignId does indeed not include quotes in the response package. – user1538142 Feb 01 '22 at 09:19
  • 1
    It feels good to be right :) – Dai Feb 01 '22 at 09:19

2 Answers2

1

The mormot API that was returning the response, didn't add quotes around campaignId, because it used its own extended JSON format.

It used the extended JSON format, because the User Agent wasn't set in the request header.

Adding a default header to my httpclient, made it work:

var client = new HttpClient();
var productValue = new ProductInfoHeaderValue("A Header", "1.0");
var commentValue = new ProductInfoHeaderValue("(a comment)");

client.DefaultRequestHeaders.UserAgent.Add(productValue);
client.DefaultRequestHeaders.UserAgent.Add(commentValue);
user1538142
  • 87
  • 1
  • 7
  • Consider caching a `static readonly ProductInfoHeaderValue` to reduce GC allocations. – Dai Feb 01 '22 at 11:25
0

You can try to add to your HttpClient this header, maybe it can help

client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

But I highly recommend you to use Newtonsoft.Json. Any another serialiazers are only good for serializing "Hello World!" . Using Newtonsoft.Json I could parse your json without any problem

using Newtonsoft.Json;


var json="{\"result\":[{CampaignId:1}]}";
    
var jsonObject= JObject.Parse(json);

if you want to fix your json, just convert parsed object to json again

json=jsonObject.ToString();

result

{
  "result": [
    {
      "CampaignId": 1
    }
  ]
}

now you can use any serializer you like. If you are using net API, maybe it is better if you show us your APi code, and your startup code too. We could help you to assign another serializer to Api controller and it will return json in a right format.

Serge
  • 40,935
  • 4
  • 18
  • 45