1

I've written my first REST API service via my ASP.Net 4.5.2 Web Application, which accept JSON data (via POST) and returns JSON data.

When I call the service using PowerShell, the returned JSON is exactly as required, and using $returnData | ConvertTo-Json works as expected allowing access to the object...

 {"result":"ok"} 

But when I call the service using RestMan on Chrome the result appears to be double-encoded...

 "{\"result\":\"ok\"}" 

I've also checked the developer tools in Chrome and the response tab shows this double-encoding, despite the response header containing Content-Type: application/json; charset=utf-8... which says to me this isn't a problem with RestMan, but my gut feeling is that it isn't an issue with Chrome either.

I've breakpointed on the final Return in the code, and the return string is definitely correct... it is not double-encoded.

I am not specifically setting the content type, .Net appears to be doing that for me, but I've tried setting it via HttpContext.Current.Response.ContentType and it doesn't make any difference.

What am I doing wrong?!

13
  • How exactly are you calling it in PowerShell? Maybe you are doing the same there - double-decoding it, once by PowerShell itself by using Invoice-RestMethod which already handles JSON for you (unlike Invoke-WebRequest) and once by another manual call to ConvertFrom-Json? Commented Apr 1, 2020 at 12:45
  • And I'd guess that you have the same issue on the server side - once it's already getting encoded automatically (since ASP.NET will automatically return the right format based on content negotiation, defaulting to JSON if no supported Accept header was sent), and maybe you additionally call JsonSerializer.Serialize and encode it a second time... Commented Apr 1, 2020 at 12:46
  • 1
    I assume what happens is this: You have an object, you call JsonSerializer.serialize on it, turning it into a string. Then you return it, and ASP.NET JSON-encodes your string, resulting in a double-encoded object string. Invoke-RestMethod receives that string and decodes it, resulting in the original once-encoded string representation of the object, and you then call ConvertFrom-Json to resolve that second layer of encoding, getting back the original object. Commented Apr 1, 2020 at 12:49
  • 1
    I'm definitely not calling a 2nd Serialize << from your perspective it'd be the 1st - which is apparent from your stating that it is returning a string already! It is returning it to ASP.NET which will nicely encode it for you to send your value as JSON... Which already was JSON before, since you serialized it manually (unnecessarily). That's what I think Commented Apr 1, 2020 at 12:50
  • 1
    To sum up what I was trying to say: ASP.NET auto-encodes for you, and Invoke-RestMethod auto-decodes for you. So no need to manually encode or decode anything, otherwise it ends up getting encoded twice, which seems to be what happened here. You can just return an object. - I'm pretty convinced now that this is what's going on, so I'll turn it into an answer Commented Apr 1, 2020 at 12:53

1 Answer 1

2

It would appear that you have two layers of JSON encoding: One done already by your tools (ASP.NET and Invoke-RestMethod in PowerShell), and one done by yourself manually.

Server side:

  1. You have an object containing a key result with value ok.
  2. You call JsonSerializer.Serialize on that object, turning it into a string (a JSON string representing the object): {"result":"ok"}
  3. You return this string from your request handler method.
  4. ASP.NET takes your value and serializes it to JSON (again!), turning it into another string (a JSON string representing another JSON string representing the object): "{\"result\":\"ok\"}"
  5. This double-encoded data is sent over the wire and returned in the HTTP request.

Client side:

  1. PowerShell receives the raw string "{\"result\":\"ok\"}" from your server.
  2. Since the content type is application/json, the Invoke-RestMethod function deserializes it for you, resulting in a new string value {"result":"ok"}, which is the original data returned from your request handler (a JSON string representing your object)
  3. You call ConvertFrom-Json on that string, deserializing it a second time, resulting in an object containing a key result and value ok.

You see, if you'd just neither manually serialize nor manually deserialize your data but instead simply return an object and treat $returnData as object too (since your tools on both ends of the wire already take care of that for you anyway), you would end up with the same result, but you'd get the expected once-encoded JSON string over the wire instead of the twice-encoded one you see now.

Sign up to request clarification or add additional context in comments.

1 Comment

Great write-up... you definitely deserve the credit on that. Thanks for the link to yet another useful Rick Strahl blog... I'll have a look and if I have more problem create a new question. Thanks for your time and efforts,it's very much appreciated :-)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.