C
C#2y ago
RiamuYui

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
square.
square.2y ago
maybe you have a null param?
RiA
RiA2y ago
did you try var response = ....... as OSMResponseModel;
RiamuYui
RiamuYui2y ago
Same error as in the json is returning a null parameter?
RiA
RiA2y ago
check if the stream the deserializer is supposed to parse isn't null
RiamuYui
RiamuYui2y ago
as in the raw json?
RiA
RiA2y ago
additionally green squigle means it's might be null. you're not initializing display_name with a non null value either use string? instead perhaps
RiamuYui
RiamuYui2y ago
surely 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
RiA
RiA2y ago
can't find a 'source' param in JsonSerializer class. maybe try logging the error or have a breakpoint
square.
square.2y ago
can u share the response body? you might be trying to parse a json array instead of a json object containing an array
RiamuYui
RiamuYui2y ago
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
I put one over the serialization and it goes to the error and says 404
square.
square.2y ago
i think you need to be returning a
{
[
{
}
]
}
{
[
{
}
]
}
for it to parse properly
RiA
RiA2y ago
i dont think that's the issue
RiamuYui
RiamuYui2y ago
i believe that's there
RiamuYui
RiamuYui2y ago
to do it synchronously how would i go about it
square.
square.2y ago
the response is of type OSMOutputs ur trying to parse it into type OSMResponseModel
RiA
RiA2y ago
no OSMOutput is just a member of OSMResponseModel
RiamuYui
RiamuYui2y ago
it didn't enjoy being parsed as OSMOutputs at all
Cisien
Cisien2y ago
Your model is expecting the json to have one property thats an array at the root But the json you posted isnt that
RiamuYui
RiamuYui2y ago
Agreed, I don't know how to parse it all as one though
Cisien
Cisien2y ago
What does the full raw json look like?
RiamuYui
RiamuYui2y ago
{"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"]}
RiA
RiA2y ago
if you need to concatenate and serialize, you can create another type and have the two types as members of it
Cisien
Cisien2y ago
What? So you only get exactly one entry?
square.
square.2y ago
no need to concatenate though, serializer would just drop properties not found in the model
RiA
RiA2y ago
class Thing3 { Thing1; Thing2; }, then serialize Thing3 instead of 1 and 2
square.
square.2y ago
iirc
RiamuYui
RiamuYui2y ago
all i want to do is retrieve the variables of lat lon and display_name from the json
Cisien
Cisien2y ago
Using your OSMOutouts class as the parameter to postasjsonasync should work
square.
square.2y ago
i aspire to attain the level of verbosity that this man displays when explaining code
RiamuYui
RiamuYui2y ago
Cisien
Cisien2y ago
You can try postasync, and read the content as a string to see what you get back
RiA
RiA2y ago
this is what i was trying to say earlier. just didn't know the syntax for it
Cisien
Cisien2y ago
Response.content.reasasstringasync
RiamuYui
RiamuYui2y ago
RiamuYui
RiamuYui2y ago
if i switch the capitalisation it does nothing either
square.
square.2y ago
response is already of type OSMOutputs
Cisien
Cisien2y ago
That was phone text
RiA
RiA2y ago
i think Cisien meant use PostAsync instead of GetFromJsonAsync
Cisien
Cisien2y ago
Client.PostAsync Then read the content Or GetAsync i guess
RiamuYui
RiamuYui2y ago
Replacing GetFromJsonAsync with either of those shows the error "cannot be used with type arguments"
RiA
RiA2y ago
remove the generic <...>
Cisien
Cisien2y ago
Yeah, ditch the type arg The json methods are helper extensions that wrap manually doing the deserialization
RiamuYui
RiamuYui2y ago
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 }
Cisien
Cisien2y ago
You got back an html page in json format Yeah, so figure that one out, then your code has a chance of working 🙂
square.
square.2y ago
wait, how'd you know it was a webpage? isn't it a generic http response from an api?
RiamuYui
RiamuYui2y ago
😂 why thank you, but now I have even less of an idea
RiA
RiA2y ago
look at the code, it has a useragent and html's head restful stuff are supposed to send out exactly what you need
RiamuYui
RiamuYui2y ago
okay but why would it send back this and not the json from the requestUri
Cisien
Cisien2y ago
Is long supposed to be -1?
square.
square.2y ago
oh i see it now lmao
RiamuYui
RiamuYui2y ago
in this case but it doesn't matter
RiA
RiA2y ago
means you're not targetting the correct controller. either that or your routing is wrong
RiamuYui
RiamuYui2y ago
this is my routing from earlier
RiamuYui
RiamuYui2y ago
and I'm calling that route in the HttpPost and how would I be targeting the wrong controller when I'm in the OSMLatLonController
RiA
RiA2y ago
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?
RiamuYui
RiamuYui2y ago
currently am
RiamuYui
RiamuYui2y ago
RiA
RiA2y ago
now compare that vs the route of the method you're expecting your json from
RiA
RiA2y ago
i mean the routing setup of that method
RiamuYui
RiamuYui2y ago
what do you mean? I don't follow
RiA
RiA2y ago
the route attribute in your controller methods the method that delivers the json
RiamuYui
RiamuYui2y ago
as in
RiA
RiA2y ago
yeah that
RiamuYui
RiamuYui2y ago
yeah it seems the same
RiA
RiA2y ago
and what are you returning
RiamuYui
RiamuYui2y ago
I thought i was returning the raw json from the api
RiA
RiA2y ago
what returned the html? PostAsync? or the result of this method
RiamuYui
RiamuYui2y ago
the GetAsync
RiA
RiA2y ago
yes i'm asking you to check the routing of where you're recieving for GetAsync from
RiamuYui
RiamuYui2y ago
is the route not GetAsync($"/reverse?format=json&limit=1&{osmLatLonModel.LLQueryString()}", cancellationToken);
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
by the other end do you mean my LLQueryString?
RiA
RiA2y ago
yes
RiamuYui
RiamuYui2y ago
this seems right too
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
it's sending the get to the domain
RiA
RiA2y ago
check the method that handles that get request
RiamuYui
RiamuYui2y ago
the OSMLatLonController is said method is it not?
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
all the GetAsync() is being sent is my LLQueryString
RiA
RiA2y ago
i thought the html page was what it was sending back
RiamuYui
RiamuYui2y ago
it is, you're correct. and I don't understand
RiA
RiA2y ago
is it supposed to send back an html page? no, right?
RiamuYui
RiamuYui2y ago
no it's meant to send back the json i sent at the beginning hence the confusion
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
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
RiA
RiA2y ago
here you're calling GetAsync who handles the request that GetAsync makes?
RiamuYui
RiamuYui2y ago
As in what is the definition of GetAsync?
RiA
RiA2y ago
Surely GetAsync doesn't request from the same method you're in, does it?
RiamuYui
RiamuYui2y ago
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?
RiA
RiA2y ago
no it's making a request with that string
RiamuYui
RiamuYui2y ago
I really don't understand, GetAsync isn't requesting anything from me but rather the api
RiA
RiA2y ago
yes so the API isn't sending you the correct data find out what the correct API is then
RiamuYui
RiamuYui2y ago
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
RiA
RiA2y ago
but you're recieving an html page in swagger too isn't it
RiamuYui
RiamuYui2y ago
yes
RiA
RiA2y ago
then check if your postman uri and this one matches
RiamuYui
RiamuYui2y ago
they're identical i copy it from my code, put it in postman and bam it works
RiA
RiA2y ago
i'm not quite sure how postman parses the data so i can't give you a definitive about that
RiamuYui
RiamuYui2y ago
so this is postman
RiA
RiA2y ago
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'
RiamuYui
RiamuYui2y ago
oookay so i add the header applicatoin/json? yknow but spelled correctly
RiA
RiA2y ago
are you using a tcpclient instead of an httpclient by any chance?
RiamuYui
RiamuYui2y ago
nope httpclientfactory
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
my browser also displays the data no problem
RiA
RiA2y ago
html serialized as json, yes?
RiamuYui
RiamuYui2y ago
I don't know how to decipher that
RiA
RiA2y ago
screenie?
RiamuYui
RiamuYui2y ago
RiA
RiA2y ago
right click > view source
RiamuYui
RiamuYui2y ago
RiA
RiA2y ago
that is certainly odd try deserializing the result from your GetAsync into an HTTPResponse object and try to get the content from it
RiamuYui
RiamuYui2y ago
Right how does one do that
RiA
RiA2y ago
you already have the string so json deserialize to the HttpResponse type
RiA
RiA2y ago
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
RiamuYui
RiamuYui2y ago
okay how does deserializing httpresponses work in this case
RiA
RiA2y ago
<HttpResponse> yeah check the deserialize api description and fill in accordingly mouseover 'deserialize'
RiamuYui
RiamuYui2y ago
what am i missing here
RiA
RiA2y ago
response mouseover response and see why it has a red squiggle under it
RiamuYui
RiamuYui2y ago
and the
RiamuYui
RiamuYui2y ago
but doing so breaks it
RiA
RiA2y ago
?! just mouse over the red squiggle
RiamuYui
RiamuYui2y ago
i did, that's the first screenshot
RiA
RiA2y ago
nevermind didn't see the other half
RiamuYui
RiamuYui2y ago
nw
RiA
RiA2y ago
which jsondeserializer is it System.Text.Json?
RiamuYui
RiamuYui2y ago
yes
RiA
RiA2y ago
wait a sec
Pobiega
Pobiega2y ago
you can't do Deserialize(response);
RiA
RiA2y ago
that looks like you're already getting a HttpResponseMessage
Pobiega
Pobiega2y ago
because response is a HttpResponseMessage you need to get the .Content property out of it and read the content
RiA
RiA2y ago
exactly
Pobiega
Pobiega2y ago
ie, var content = await response.Content.ReadAsStringAsync();
RiamuYui
RiamuYui2y ago
RiamuYui
RiamuYui2y ago
WAIT I DID IT
Pobiega
Pobiega2y ago
your model class you are attempting to deserialize to..
RiamuYui
RiamuYui2y ago
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
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
RiA
RiA2y ago
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
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
I appreciate the help nonetheless
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
but while im at it, why isn't this select working 😂
RiamuYui
RiamuYui2y ago
yes?
Pobiega
Pobiega2y ago
because content is a string
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
.Select over a string will iterate over the individual chars
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiA
RiA2y ago
you'll have to deserialize that content again into your model
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiA
RiA2y ago
HttpResponseMessage.Content extract the actual content from the http response data. then deserialization is upto you
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
Pobiega
Pobiega2y ago
you'll need to set a [JsonConstructor] attribute on the ctor
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX2y ago
RiamuYui#6195
Quoted by
From RiamuYui#6195
React with ❌ to remove this embed.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
there is plenty of reason to do that
RiamuYui
RiamuYui2y ago
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiA
RiA2y ago
content is a json string currently
Pobiega
Pobiega2y ago
he doesnt want the string thou, he wants the data
RiA
RiA2y ago
they need to deserialize it into the model first, then they can use Linq on it
RiamuYui
RiamuYui2y ago
okay deserializing the data manually look something like this?
RiamuYui
RiamuYui2y ago
i had this before but it never got to see any use
Pobiega
Pobiega2y ago
your models need to match the json structure exactly
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
as in in order too?
Pobiega
Pobiega2y ago
can you paste the json you got here, in a code block?
RiamuYui
RiamuYui2y ago
like none of the values are nested
RiA
RiA2y ago
i dont think order matters. only the hierarchy
Pobiega
Pobiega2y ago
yeah, hierarchy, types, and names
RiamuYui
RiamuYui2y ago
i can paste the json but how do i do it in a code block
RiA
RiA2y ago
and names yeah
Pobiega
Pobiega2y ago
$code
MODiX
MODiX2y ago
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
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
{
"place_id": 128834247,
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "way",
"osm_id": 100490251,
"lat": "51.9988103",
"lon": "-0.9985512",
"display_name": "Tingewick Road Industrial Estate, Buckingham, Buckinghamshire, England, MK18 1FY, United Kingdom",
"address": {
"industrial": "Tingewick Road Industrial Estate",
"town": "Buckingham",
"county": "Buckinghamshire",
"state": "England",
"ISO3166-2-lvl4": "GB-ENG",
"postcode": "MK18 1FY",
"country": "United Kingdom",
"country_code": "gb"
},
"boundingbox": [
"51.9988103",
"51.9996756",
"-0.9985512",
"-0.996438"
]
}
{
"place_id": 128834247,
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "way",
"osm_id": 100490251,
"lat": "51.9988103",
"lon": "-0.9985512",
"display_name": "Tingewick Road Industrial Estate, Buckingham, Buckinghamshire, England, MK18 1FY, United Kingdom",
"address": {
"industrial": "Tingewick Road Industrial Estate",
"town": "Buckingham",
"county": "Buckinghamshire",
"state": "England",
"ISO3166-2-lvl4": "GB-ENG",
"postcode": "MK18 1FY",
"country": "United Kingdom",
"country_code": "gb"
},
"boundingbox": [
"51.9988103",
"51.9996756",
"-0.9985512",
"-0.996438"
]
}
RiA
RiA2y ago
well in this case
Pobiega
Pobiega2y ago
and you are after the display_name, lat and lon only?
RiA
RiA2y ago
yeah you can simply dser into that class then and it should hold your values
RiamuYui
RiamuYui2y ago
yes
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
yep, then get rid of your OSMResponseModel class
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
you can deserialize directly into OSMOutputs from that at the root level
RiamuYui
RiamuYui2y ago
in this case are the objects lat and lon and such or new
Pobiega
Pobiega2y ago
? they will contain the data from the json thats the entire point 🙂
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
and because your properties are not readonly ( {get;set;}), you dont need a constructor or any attributes
RiamuYui
RiamuYui2y ago
had this error The JSON value could not be converted to System.Decimal. Path: $.lat | LineNumber: 0 | BytePositionInLine: 152.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
right, latand lon should not be decimal
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
change them to strings, you shouldnt treat them as mathematical values
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
AH WONDERFUL
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
good lord that took a hefty amount of learning if you couldn't tell, I've only just started with this
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Pobiega
Pobiega2y ago
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
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
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
Pobiega
Pobiega2y ago
Good design would be using a record for your response model. wdym by "read each value"?
RiamuYui
RiamuYui2y ago
I still have that responsemodel
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
as in currently they're one long string right? and I want to assign them to variables elsewhere
Pobiega
Pobiega2y ago
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
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
can i pull them out with the LocationResult?
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
ohhh okay
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
RiamuYui
RiamuYui2y ago
yup it's working thanks so much for the help