Deserializing JSON from HttpClient
I seem to not know the syntax to deserialize the JSON I'm getting back from the api, I'm getting a 400 error "Value cannot be null. (Parameter 'source')". If anyone could give any insight that would be wonderful.
221 Replies
maybe you have a null param?
did you try
var response = ....... as OSMResponseModel;
Same error
as in the json is returning a null parameter?
check if the stream the deserializer is supposed to parse isn't null
as in the raw json?
additionally green squigle means it's might be null. you're not initializing display_name with a non null value either
use
string?
instead perhapssurely I wouldn't have to initialize display_name as anything if it is getting a result through the get request
still coming back with the error
can't find a 'source' param in JsonSerializer class. maybe try logging the error
or have a breakpoint
can u share the response body?
you might be trying to parse a json array instead of a json object containing an array
might be a good idea to catch the data entirely then do a synchronous deserialize. you'll be able to see what you're deserializing
I put one over the serialization and it goes to the error and says 404
i think you need to be returning a
for it to parse properly
i dont think that's the issue
i believe that's there
to do it synchronously how would i go about it
the response is of type OSMOutputs
ur trying to parse it into type OSMResponseModel
no OSMOutput is just a member of OSMResponseModel
it didn't enjoy being parsed as OSMOutputs at all
Your model is expecting the json to have one property thats an array at the root
But the json you posted isnt that
Agreed, I don't know how to parse it all as one though
What does the full raw json look like?
{"place_id":109189975,"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright","osm_type":"way","osm_id":22724318,"lat":"52.00201252464646","lon":"0.9994463968148076","display_name":"Wenham Magna, Little Wenham, Babergh, Suffolk, England, CO7 6PS, United Kingdom","address":{"village":"Little Wenham","city":"Babergh","county":"Suffolk","ISO3166-2-lvl6":"GB-SFK","state":"England","ISO3166-2-lvl4":"GB-ENG","postcode":"CO7 6PS","country":"United Kingdom","country_code":"gb"},"boundingbox":["52.0005781","52.0079506","0.9918249","1.0162949"]}
if you need to concatenate and serialize, you can create another type and have the two types as members of it
What?
So you only get exactly one entry?
no need to concatenate though, serializer would just drop properties not found in the model
class Thing3 { Thing1; Thing2; }, then serialize Thing3 instead of 1 and 2
iirc
all i want to do is retrieve the variables of lat lon and display_name from the json
Using your OSMOutouts class as the parameter to postasjsonasync should work
i aspire to attain the level of verbosity that this man displays when explaining code
You can try postasync, and read the content as a string to see what you get back
this is what i was trying to say earlier. just didn't know the syntax for it
Response.content.reasasstringasync
if i switch the capitalisation it does nothing either
response is already of type OSMOutputs
That was phone text
i think Cisien meant use PostAsync instead of GetFromJsonAsync
Client.PostAsync
Then read the content
Or GetAsync i guess
Replacing GetFromJsonAsync with either of those shows the error "cannot be used with type arguments"
remove the generic <...>
Yeah, ditch the type arg
The json methods are helper extensions that wrap manually doing the deserialization
okay the response im getting back is not what im expecting
{
"version": "1.1",
"content": {
"headers": [
{
"key": "Content-Type",
"value": [
"application/json; charset=utf-8"
]
}
]
},
"statusCode": 200,
"reasonPhrase": "OK",
"headers": [
{
"key": "Server",
"value": [
"nginx"
]
},
{
"key": "Date",
"value": [
"Tue, 20 Sep 2022 13:45:32 GMT"
]
},
{
"key": "Transfer-Encoding",
"value": [
"chunked"
]
},
{
"key": "Connection",
"value": [
"keep-alive"
]
},
{
"key": "Keep-Alive",
"value": [
"timeout=20"
]
},
{
"key": "Access-Control-Allow-Origin",
"value": [
"*"
]
},
{
"key": "Access-Control-Allow-Methods",
"value": [
"OPTIONS,GET"
]
}
],
"trailingHeaders": [],
"requestMessage": {
"version": "1.1",
"versionPolicy": 0,
"content": null,
"method": {
"method": "GET"
},
"requestUri": "https://nominatim.openstreetmap.org/reverse?format=json&limit=1&lat=52&lon=-1",
"headers": [
{
"key": "User-Agent",
"value": [
"Mozilla/5.0",
"(Windows NT 10.0; Win64; x64)",
"AppleWebKit/537.36",
"(KHTML, like Gecko)",
"Chrome/105.0.0.0",
"Safari/537.36",
"Edg/105.0.1343.33"
]
},
{
"key": "traceparent",
"value": [
"00-9eafc6b21c22e0e4a3382cabb1a0d5ad-02e8d08db0e28f17-00"
]
}
],
"properties": {},
"options": {}
},
"isSuccessStatusCode": true
}
You got back an html page in json format
Yeah, so figure that one out, then your code has a chance of working 🙂
wait, how'd you know it was a webpage? isn't it a generic http response from an api?
😂 why thank you, but now I have even less of an idea
look at the code, it has a useragent and html's head
restful stuff are supposed to send out exactly what you need
okay but why would it send back this and not the json from the requestUri
Is long supposed to be -1?
oh i see it now lmao
in this case but it doesn't matter
means you're not targetting the correct controller. either that or your routing is wrong
this is my routing from earlier
and I'm calling that route in the HttpPost
and how would I be targeting the wrong controller when I'm in the OSMLatLonController
the wrong route then perhaps. tldr it's supposed to be a json response but you're getting a view instead
maybe using swagger will help?
currently am
now compare that vs the route of the method you're expecting your json from
yeah it seems right https://localhost:7133/api/osm/get-location-ll
i mean the routing setup of that method
what do you mean? I don't follow
the route attribute in your controller methods
the method that delivers the json
as in
yeah that
yeah it seems the same
and what are you returning
I thought i was returning the raw json from the api
what returned the html? PostAsync? or the result of this method
the GetAsync
yes
i'm asking you to check the routing of where you're recieving for GetAsync from
is the route not GetAsync($"/reverse?format=json&limit=1&{osmLatLonModel.LLQueryString()}", cancellationToken);
on this end of your method yes
check what the other end is doing
because if it's not sending you the correct data, then something isn't working as it's supposed to on the other end
by the other end do you mean my LLQueryString?
yes
this seems right too
GetAsync send a request and recieves it async
you're getting an html page instead of a json response
so wherever you're sending that Get to, isn't sending you the correct data
that's what i mean
so check the code on that end
it's sending the get to the domain
check the method that handles that get request
the OSMLatLonController is said method is it not?
i dont think so
while you're handling a request, you're also making another internal request
which is the GetAsync()
that's the method that isn't providing the correct data for you, so find out where that data is being sent from and correct it
all the GetAsync() is being sent is my LLQueryString
i thought the html page was what it was sending back
it is, you're correct. and I don't understand
is it supposed to send back an html page?
no, right?
no it's meant to send back the json i sent at the beginning
hence the confusion
yes. so that means wherever you're calling with the GetAsync()
isn't delivering the correct data to you
you need to find out what THAT controller is doing. not the one you're in right now
I haven't written another controller
unless i'm mistaken
I'm only calling the GetAsync in this controller
I have a query model, a response model, a definition for locationresult and the controller
i guess and the routing
here you're calling GetAsync
who handles the request that GetAsync makes?
As in what is the definition of GetAsync?
Surely GetAsync doesn't request from the same method you're in, does it?
Isn't GetAsync requesting the string I put into it so in this case $"/reverse?format=json&limit=1&{osmLatLonModel.LLQueryString()}"
and that's it no?
no it's making a request with that string
HttpClient.GetAsync Method (System.Net.Http)
Send a GET request to the specified Uri as an asynchronous operation.
I really don't understand, GetAsync isn't requesting anything from me but rather the api
yes so the API isn't sending you the correct data
find out what the correct API is then
but im using this exact api in postman and in by browser and it works fine
I've added a user agent to get it past the not found error
but you're recieving an html page in swagger too isn't it
yes
then check if your postman uri and this one matches
they're identical
i copy it from my code, put it in postman and bam it works
i'm not quite sure how postman parses the data so i can't give you a definitive about that
so this is postman
okay that isn't an html page but an http wrapped file
that actually says the mimetype is an application/json
in which the content is 'null'
oookay
so i add the header applicatoin/json?
yknow but spelled correctly
are you using a tcpclient instead of an httpclient by any chance?
nope httpclientfactory
do the same request in a browser and see view the source?
nevermind i'm being dumb
the html data itself is 'serialized' in json when it's being sent to you
which means
while the json is already null, it's placed into an html page, then the TCP data of the page itself is serialized into a json.
something is wrong with either the api you're supposed to use, or postman handles deserialization of the http headers and is able to extract just the content from it
my browser also displays the data no problem
html serialized as json, yes?
I don't know how to decipher that
screenie?
right click > view source
that is certainly odd
try deserializing the result from your GetAsync into an HTTPResponse object
and try to get the content from it
Right how does one do that
you already have the string
so json deserialize to the HttpResponse type
HttpResponse Class (Microsoft.AspNetCore.Http)
Represents the outgoing side of an individual HTTP request.
the objects signature is kinda similar to the page you got back
might actually work
for whatever reason, your api is serializing an httpresponse into a json, i think
either that or it's standard procedure to deserialize after GetAsync. idk
okay how does deserializing httpresponses work in this case
<HttpResponse>
yeah
check the deserialize api description and fill in accordingly
mouseover 'deserialize'
what am i missing here
response
mouseover response and see why it has a red squiggle under it
and the
but doing so breaks it
?!
just mouse over the red squiggle
i did, that's the first screenshot
nevermind didn't see the other half
nw
which jsondeserializer is it
System.Text.Json?
yes
wait a sec
you can't do
Deserialize(response);
that looks like you're already getting a HttpResponseMessage
because response is a
HttpResponseMessage
you need to get the .Content
property out of it and read the contentexactly
ie,
var content = await response.Content.ReadAsStringAsync();
WAIT
I DID IT
your model class you are attempting to deserialize to..
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
I don't, I have finally read the json out of the api, I now need to just set lat, lon and display_name as variables
that html page put me off. i thought it was a string. you should check the type you're getting back. mouse over more often!
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
I appreciate the help nonetheless
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
but while im at it, why isn't this select working 😂
yes?
because
content
is a stringUnknown User•3y ago
Message Not Public
Sign In & Join Server To View
.Select
over a string will iterate over the individual char
sUnknown User•3y ago
Message Not Public
Sign In & Join Server To View
you'll have to deserialize that content again into your model
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
HttpResponseMessage.Content extract the actual content from the http response data. then deserialization is upto you
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
you'll need to set a
[JsonConstructor]
attribute on the ctorUnknown User•3y ago
Message Not Public
Sign In & Join Server To View
RiamuYui#6195
Quoted by
<@!105026391237480448> from #Deserializing JSON from HttpClient (click here)
React with ❌ to remove this embed.
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
there is plenty of reason to do that
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
content is a json string currently
he doesnt want the string thou, he wants the data
they need to deserialize it into the model first, then they can use Linq on it
okay deserializing the data manually look something like this?
i had this before but it never got to see any use
your models need to match the json structure exactly
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
as in in order too?
can you paste the json you got here, in a code block?
like none of the values are nested
i dont think order matters. only the hierarchy
yeah, hierarchy, types, and names
i can paste the json but how do i do it in a code block
and names yeah
$code
To post C# code type the following:
```cs
// code here
```
Get an example by typing
$codegif
in chat
If your code is too long, post it to: https://paste.mod.gg/
To post C# code type the following:
```cs
// code here
```
Get an example by typing $codegif
in chat
If your code is too long, post it to: https://paste.mod.gg/Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
well in this case
and you are after the
display_name
, lat
and lon
only?yeah you can simply dser into that class then and it should hold your values
yes
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
yep, then get rid of your
OSMResponseModel
classUnknown User•3y ago
Message Not Public
Sign In & Join Server To View
you can deserialize directly into
OSMOutputs
from that at the root levelin this case are the objects lat and lon and such or new
?
they will contain the data from the json
thats the entire point 🙂
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
and because your properties are not readonly (
{get;set;}
), you dont need a constructor or any attributeshad this error The JSON value could not be converted to System.Decimal. Path: $.lat | LineNumber: 0 | BytePositionInLine: 152.
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
right,
lat
and lon
should not be decimal
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
change them to strings, you shouldnt treat them as mathematical values
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
AH WONDERFUL
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
good lord that took a hefty amount of learning
if you couldn't tell, I've only just started with this
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
So much ego.
The reason I brought up
JsonConstructor
was because in his previous code, his response model was read only and had a constructor.
and thats fine, but then it REQUIRES that attribute to work.Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
guys we solved it, it's all good. I don't have to edit them, just read them from elsewhere in the code
speaking of, if I'm returning osmOutputs, can I read each value individually
Good design would be using a record for your response model.
wdym by "read each value"?
I still have that responsemodel
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
as in currently they're one long string right? and I want to assign them to variables elsewhere
you are returning an instance of an object with the values set to whatever the API responded with
they are not a string
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
can i pull them out with the LocationResult?
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
ohhh
okay
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
yup it's working
thanks so much for the help