I have a json response from an API that returns back with a name value where which starts with an #.
For example:
{
"#id": "Something",
"url": "www.example.com",
"username": "Bob",
}
I am trying to load this with the generic GetAsync method into an object like:
RestClient restClient = new RestClient("https://api.somewebsite.com/pub");
var request = new RestRequest($"user/Bob");
var actUser = await restClient.GetAsync<User>(request)
This is working fine for all name/value pairs, but I cannot get RestSharp to initialize #id.
In my User class I have tried:
public string id { get; set; }
and
[JsonProperty("id")]
public string ID { get; set; }
and
[JsonProperty("#id")]
public string ID { get; set; }
but it is always null.
Is there a way to get the #id value?
try this, it works for me
using Newtonsoft.Json;
var restResponse = await restClient.ExecuteTaskAsync(request);
User user = JsonConvert.DeserializeObject<User>( restResponse.Content);
public class User
{
[JsonProperty("#id")]
public string Id { get; set; }
public string url { get; set; }
public string username { get; set; }
}
I think GetAsync uses Text.Json so you can try
[JsonPropertyName("#id")]
public string Id { get; set; }
but IMHO ExecuteTaskAsync is more flexible since you can use any Newtonsoft.Json or System.Text.Json options.
Related
I'm trying and failing to write a program that will make an API call and then turn the returned items into objects that fit my model. Specifically I can't make it deserealize, and I suspect it has something to do with how the json is return compared to what my model looks like.
The data I'm trying to get looks like this;
https://api.nasa.gov/planetary/apod?start_date=2022-03-01&end_date=2022-03-08&api_key=DEMO_KEY
As you can see, it consists of an array of items, but there is no name for the array items. When I paste this into the Get-model with Paste JSON as Classes, I get this;
public class GetApodItemsResult
{
public Class1[] Property1 { get; set; }
}
public class Class1
{
public string copyright { get; set; }
public string date { get; set; }
public string explanation { get; set; }
public string hdurl { get; set; }
public string media_type { get; set; }
public string service_version { get; set; }
public string title { get; set; }
public string url { get; set; }
}
My entire code works just fine up until I need to serialize the JSON with this line:
var responseObject = await response.Content.ReadFromJsonAsync<GetApodItemsResult>();
, where I get this message;
System.Text.Json.JsonException: 'The JSON value could not be converted to UnnamedSpaceProject.Models.GetApodItemsResult.
Interestingly I know that the code works on a spotify api call, so the code really should work largely the same, which leads me to believe that the problem is with how the JSON is formatted.
How do I get around that? Because I don't see a way to have the root object contain an unnamed array.
Your GetApodItemsResult class is not a valid class to deserialize the content you get from server, the correct deserialization type will be List<Class1> or Class1[]
var responseObject = await response.Content.ReadFromJsonAsync<List<Class1>>();
I recommend you to use more meaningful name instead of Class1 you can name it Apod (acronym for Astronomy Picture of the Day)
Full working code:
using System.Text.Json;
using System.Text.Json.Serialization;
HttpClient client = new HttpClient();
const string BaseUrl = #"https://api.nasa.gov/";
var response = await client.GetAsync($"{BaseUrl}planetary/apod?start_date=2022-03-01&end_date=2022-03-08&api_key=DEMO_KEY");
if ((response.StatusCode != System.Net.HttpStatusCode.OK))
{
Console.Error.WriteLine("field to fetch data from server");
}
var responseBody = await response.Content.ReadAsStringAsync();
var pictuersList = JsonSerializer.Deserialize<List<Apod>>(responseBody);
Console.WriteLine($"there is {pictuersList?.Count} apod downloaded successflly");
Console.WriteLine("done");
public class Apod
{
[JsonPropertyName("copyright")]
public string Copyright { get; set; } = "";
[JsonPropertyName("date")]
public string Date { get; set; } = "";
[JsonPropertyName("explanation")]
public string Explanation { get; set; } = "";
[JsonPropertyName("hdurl")]
public string Hdurl { get; set; } = "";
[JsonPropertyName("media_type")]
public string MediaType { get; set; } = "";
[JsonPropertyName("service_version")]
public string ServiceVersion { get; set; } = "";
[JsonPropertyName("title")]
public string Title { get; set; } = "";
[JsonPropertyName("url")]
public string Url { get; set; } = "";
}
The object your JSON containing is not some container with the array in it, it IS the array. So, the correct code would be like this:
var responseObject = await response.Content.ReadFromJsonAsync<Class1[]>();
The correct JSON for your code would look like this:
{
"Property1": [{
"copyright": "Jeff DaiTWAN",
"date": "2022-03-01",
"url": "https://apod.nasa.gov/apod/image/2203/DuelingBands_Dai_960.jpg"
}]
}
I'm fairly new to rest apis and tried to follow some simple tutorials. Using some test Uri's I get
a response for a server-object that looks like this:
{
"server": {
"id": 123456,
"name": "srv-ubuntu-01",
"status": "running",
"created": "2021-01-11T13:04:24+00:00"
}
}
Usually I'd be able to deserialize this using NewtonSoft.Json with
var server = JsonConvert.DeserializeObject<XServer>(jsonString);
using given class:
public class XServer
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("status")]
public String Status { get; set; }
[JsonProperty("created")]
public DateTime DateCreate { get; set; }
}
However, in this case this doesen't work because the json response from the server holds the server object as a "sub-object" ((?) I don't know the correct term). So I figured I could use following code as a workaround:
var def = new { server = new Object() };
var defObj = JsonConvert.DeserializeAnonymousType(jsonString, def);
var obj = JsonConvert.DeserializeObject<XServer>(defObj.server.ToString());
But that can't be it, right? Obviously there is something I'm missing... at least I think so. Any input is appreciated, as mentioned, I'm a beginner, eager to learn ;)
Your Root Object has the key, server which has the object XServer.
Deserialize to RootObject to access the server object, 'XServer'.
public class RootObject {
[JsonProperty("server")]
public XServer Server {get; set;}
}
var obj = JsonConvert.DeserializeObject<RootObject>(jsonString);
XServer server = obj.Server;
=========== Solution ===========
So using #madreflections input I came to following solution, which works perfectly fine:
public class XServerRootObject
{
[JsonProperty("server")]
public XServer Server { get; set; }
}
public class XServer
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("status")]
public String Status { get; set; }
[JsonProperty("created")]
public DateTime DateCreate { get; set; }
}
Using the root object as following:
public XServer GetServer(int id)
{
var req = new RestRequest("/servers/" + id, Method.GET, DataFormat.Json);
req.AddHeader("authorization", "Bearer " + _token);
var json = _client.Get(req).Content;
var srvRoot = JsonConvert.DeserializeObject<XServerRootObject>(json);
return srvRoot.Server;
}
I'm authenticating to google in a Xamarin.Forms app. Once authenticated I want to retrieve user email, and use this code that I adapted from this blog, the code for retrieving the email:
public class GoogleProfile
{
[Preserve]
[JsonConstructor]
public GoogleProfile() { }
public string sub { get; set; }
public string name { get; set; }
public string given_name { get; set; }
public string profile { get; set; }
public string picture { get; set; }
public string email { get; set; }
public string email_verified { get; set; }
public string locale { get; set; }
}
public class GoogleService
{
public async Task<string> GetEmailAsync(string tokenType, string accessToken)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
var json = await httpClient.GetStringAsync("https://www.googleapis.com/oauth2/v3/userinfo");//https://www.googleapis.com/userinfo/email?alt=json");
var profile = JsonConvert.DeserializeObject<GoogleProfile>(json);
return profile.email;
}
}
Now, with a breakpoint in the last line return profile.email I've "seen" the json file that is this way:
{
"sub": "",
"name": "",
"given_name": "",
"profile": "",
"picture": "",
"email": "",
"email_verified": "",
"locale": "",
}
Between the quotes are the data, obviously.
I'm not really accustomed to JSon but reading this I thought that the format is simply "nameOfProperty":"ValueOfProperty", so I made GoogleProfile object.
I read too that the attributes [Preserve] and [JsonConstructor] are necessary so the linker doesn't just "remove" empty constructors when compiling.
There are no exceptions and no apparent problems, but if I put a breakpoint in the last return profile.email; line, I can see the json object has all the data and is perfectly fine, but the profile object have only the email property with value null...
I don't understand it: what happened with the other properties? Is it even possible? You know, you code an object with a bunch of properties but the object are created with only one of those properties? If the object had all the properties with a value of null, Ok, but where did the other properties gone?
Just to be sure, I've cleaned and rebuild projects and solution, I've removed bin and obj folders and then clean and rebuild again... I've done the obvious things.
Thing is that as you can see in the blog I mentioned earlier, first I didn't use GoogleProfile object, I just copied the object in the blog... that has only one property called email. Is it possible that visual studio or xamarin or something got bugged and the changes didn't got reflected? I doubt it because I've changed the URI used in the GetStringAsync method and it did got reflected, but well, I don't know.
PD: In the meanwhile I'm parsing the JSON directly as a normal string, it's a simple object and I only really need the email, but well, it would be a shame that I'd have to parse it that way instead of just deserialize it.
Edit:
As suggested by Skin in the comments I've used http://jsonutils.com/
One of the properties was a bool (of course), so I've changed it and the object now is:
public class GoogleProfile
{
[Preserve]
[JsonConstructor]
public GoogleProfile() { }
public string sub { get; set; }
public string name { get; set; }
public string given_name { get; set; }
public string profile { get; set; }
public string picture { get; set; }
public string email { get; set; }
public bool email_verified { get; set; }
public string locale { get; set; }
}
But it didn't change the result, still happening the same. Image of the result at the breakpoint:
I don't think there is any problem with your code. I used the same code of you and didn't change anything. I use my own tokenType and accessToken.
My steps:
copy your code to my project.
get my own token by using the project in the blog
install newtonsoft Nuget package
run the project and get result
So, is there any problem with your account? Did you account have an e-mail? Any difference with mine?
Here is what I get:
Code:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
testAsync();
}
public async Task testAsync()
{
GoogleService googleS = new GoogleService();
// use your token here
var email = await googleS.GetEmailAsync("", "");
Console.WriteLine(email);
}
public class GoogleProfile
{
[Preserve]
[JsonConstructor]
public GoogleProfile() { }
public string sub { get; set; }
public string name { get; set; }
public string given_name { get; set; }
public string profile { get; set; }
public string picture { get; set; }
public string email { get; set; }
public string email_verified { get; set; }
public string locale { get; set; }
}
public class GoogleService
{
public async Task<string> GetEmailAsync(string tokenType, string accessToken)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var json = await httpClient.GetStringAsync("https://www.googleapis.com/oauth2/v3/userinfo");//https://www.googleapis.com/userinfo/email?alt=json");
var profile = JsonConvert.DeserializeObject<GoogleProfile>(json);
Console.WriteLine(json);
Console.WriteLine(profile);
return profile.email;
}
}
}
This question already has answers here:
Private setters in Json.Net
(5 answers)
Closed 4 years ago.
I am trying to deserialise the json into custom class list using Newtonsoft.Json.
Here is my code:
public List<EmployeeModel> getEmployee()
{
string Baseurl = "http://dummy.restapiexample.com/api/v1/";
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
var EmpResponse = new List<EmployeeModel>();
var Res = client.GetAsync("employees");
Res.Wait();
var result = Res.Result;
//Checking the response is successful or not which is sent using HttpClient
if (result.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var r = result.Content.ReadAsStringAsync().Result;
EmpResponse = JsonConvert.DeserializeObject<List<EmployeeModel>>(r);
//Deserializing the response recieved from web api and storing into the Employee list
}
//returning the employee list to view
return EmpResponse;
}
}
When I check the variable r value I am getting following Json String:
[
{
"id": "317",
"employee_name": "Nitza",
"employee_salary": "775",
"employee_age": "1",
"profile_image": ""
},
{
"id": "318",
"employee_name": "Nitza Ivri",
"employee_salary": "10000",
"employee_age": "33",
"profile_image": ""
}
]
Also, my model code is as per below:
public class EmployeeModel
{
public string id { get; private set; }
public string employee_name { get; private set; }
public string employee_salary { get; private set; }
public string employee_age { get; private set; }
}
The reason is that your properties in EmployeeModel has private set. You need to remove private from your properties then it would be able to deserialize successfully. Your entity should be like following:
public class EmployeeModel
{
public string id { get; set; }
public string employee_name { get; set; }
public string employee_salary { get; set; }
public string employee_age { get; set; }
}
Also, your EmployeeModel does not contain property profile_image. You need to add this property to your model.
If it is important for you to keep your properties setters as private, you can provide a constructor that has parameters like:
public class EmployeeModel
{
public EmployeeModel(string id, string employee_name,string employee_salary, string employee_age, string profile_image )
{
this.id = id;
this.employee_name = employee_name;
this.employee_salary = employee_salary;
this.employee_age = employee_age;
this.profile_image = profile_image;
}
public string id { get; private set; }
public string employee_name { get; private set; }
public string employee_salary { get; private set; }
public string employee_age { get; private set; }
public string profile_image { get; private set; }
}
I am retrieving the following JSON via a POST to an API
{
"State":"Andhra_Pradesh",
"District":"Guntur",
"Fact":"SELECT",
"Description":"",
"FactDate":"",
"FactNumber":"",
"FactType":"SELECT",
"Fact":{"Id":"1"}
}
I am able to execute the Ajax request via javascript, but I also want to consume the API through C# code.
I am using the below code, but I'm not quite sure on how to add the Fact object?
var values = new Dictionary<string, string>
{
{ "State", selectedState },
{ "District", selectedDistrict },
{ "Fact", ""},
{ "FactType", ""},
{ "FactNumber", ""},
{ "Description", ""},
{"Fact", "{Id,1}" },
{"FactDate", factDate.Date.ToString() }
};
using (var httpClient = new HttpClient())
{
var content = new FormUrlEncodedContent(values);
var response = await httpClient.PostAsync("http://api.in/" + "test", content);
}
How do I add the Fact object to Dictionary?
You'll probably need to define the data you are sending as actual class before using httpclient.
If you had only name value pairs then you could have used the NameValueCollection and sent as a formurlencoded but since you have a complex type, you might consider this below.
See below.
public class Rootobject
{
public string State { get; set; }
public string District { get; set; }
public Fact Fact { get; set; }
public string Description { get; set; }
public string CaseDate { get; set; }
public string FactNumber { get; set; }
public string FactType { get; set; }
}
public class Fact
{
public string Id { get; set; }
}
Usage is as below. be sure to include a reference to System.Net.Http.Formatting.dll
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var model = new Rootobject { State = "Andhra_Pradesh", District = "Guntur", FactType = "SELECT", Description = "", CaseDate = "", FactNumber = "", Fact = new Fact { Id = "1"} };
var data = await client.PostAsJsonAsync("http://api.in/" + "test", model);
I think this is just a json object, you can either create a class which have the same properties of (state, district etc ..) and use json serializer
or you can create JObject using Json.Net
You can use Newtonsonft.Json to to the serializaton/deserialization job and the code will be like that.
public class Rootobject
{
[JsonProperty("State")]
public string State { get; set; }
[JsonProperty("District")]
public string District { get; set; }
[JsonProperty("Fact")]
public Fact Fact { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("CaseDate")]
public string CaseDate { get; set; }
[JsonProperty("FactNumber")]
public string FactNumber { get; set; }
[JsonProperty("FactType")]
public string FactType { get; set; }
}
public class Fact
{
[JsonProperty("Id")]
public string Id { get; set; }
}
And then, after instatiating your object, just serialize it.
Rootobject example = new Rootobject();
//Add values to the variable example.
var objectSerialized = JsonConvert.SerializeObject(example);
After that, you will have a json ready to be send wherever you want.
Just change {"Fact", "{Id,1}" } to {"Fact.Id", "1" },