C# .net http | How to get objects layers deep from API - c#

I learned how to get information from an API using the microsoft docs, the microsoft docs don't show how to get nested/layers deep objects. The only video I found that showed how to do it did it something like this. However I can't get it to work, receiving only an error stating this:
"Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Dashboard.Weather' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly."
Any help is appreciated, i'm trying to get the "Weather.description", here's my sample code:
public class Weather
{
public string Description{ get; set; }
}
public class Product
{
public Weather Weather { get; set; }
}
public static class ApiHelper
{
static string city_id = "CITY_ID";
static string api_key = "API_KEY";
public static HttpClient client = new HttpClient();
public static void InitializeClient()
{
client.BaseAddress = new Uri($"http://api.openweathermap.org/data/2.5/weather?id={city_id}&APPID={api_key}");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public static async Task<Weather> GetProductAsync()
{
Product product = null;
HttpResponseMessage response = await client.GetAsync("");
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product.Weather;
}
}
async void SetLabelText()
{
var weather = await ApiHelper.GetProductAsync();
descriptionLabel.Text = $"Description: {weather.Description}";
}
The response from the API is formatted as follows
{"coord":{"lon":-89.59,"lat":41.56},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"base":"stations","main":{"temp":279.27,"feels_like":275.4,"temp_min":278.15,"temp_max":280.37,"pressure":1027,"humidity":74},"visibility":16093,"wind":{"speed":3.1,"deg":200},"clouds":{"all":1},"dt":1576951484,"sys":{"type":1,"id":3561,"country":"US","sunrise":1576934493,"sunset":1576967469},"timezone":-21600,"id":4915397,"name":"Walnut","cod":200}

Your Product model does not correctly align with the json you are receiving.
The json you've post has weather as a list, but Product assumes it will just be an object. The json parser, then, correctly fails when seeing it is an array in the actual json instead of a JSON object.
The fix should be simple; Product.Weather should be of type List<Weather> (or IEnumerable<Weather> or Weather[], whichever fits your needs).

Related

Blazor: Cannot deserialize the current JSON object

I am creating an app in Blazor, upon getting a list of data displayed(Index View) I am running into the following error:
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
I have heard that Blazor does not support HttpClient for Injection. So I wrote a custom HttpClient to do the same job, however I ran into an issue and unable to understand why I am getting it.
Below is a copy of my entity section:
public class Tournament
{
[Key]
public int TournamentID { get; set; }
public string TournamentName { get; set; }
public virtual ICollection<Event> Events { get; set; }
}
A copy of my code section in razor page:
#code {
Tournament[] tournaments;
string baseUrl;
protected override async Task OnInitializedAsync()
{
baseUrl = AppSettingsService.GetBaseUrl();
tournaments = await Http.GetJsonAsync<Tournament[]>(baseUrl + "api/tournaments/gettournaments");
}
}
And a copy of my custom http client class:
public async Task<T> GetJsonAsync<T>(string requestUri)
{
HttpClient httpClient = new HttpClient();
var httpContent = await httpClient.GetAsync(requestUri);
string jsonContent = httpContent.Content.ReadAsStringAsync().Result;
T obj = JsonConvert.DeserializeObject<T>(jsonContent);
httpContent.Dispose();
httpClient.Dispose();
return obj;
}
Can anyone help me further in this regard?
Thanks.

How call WebAPI method in MVC and send the json object to it

I need to call this method in MVC controller and pass the UpdateRequest object as json format. how I can do that?
[HttpPost]
[Route("updatecertificate")]
public void updatecertificate([FromBody] UpdateRequest certificatereviewed)
{
loansRepository.updatecertificate(certificatereviewed.Id, certificatereviewed.CertificateReview);
}
and this is the input class:
public class UpdateRequest {
public int Id { get; set; }
public bool CertificateReview { get; set;}
}
this is how I call and send separate variable but now I like to send the class object in json format.
private async Task UpdateFundingCertificateReviewed(int id, bool fundingCertificateReviewed)
{
await httpClient.PostAsync(string.Format("{0}/{1}", LoanApiBaseUrlValue, updatecertificate),null);
}
I personally like Newtonsoft.Json to serialize the object.
private async Task UpdateFundingCertificateReviewed
(int id, bool fundingCertificateReviewed)
{
using (var client = new HttpClient())
{
var url = string.Format("{0}/{1}", LoanApiBaseUrlValue, updatecertificate);
var updateRequest = new UpdateRequest { Id = 1, CertificateReview = true};
var data = JsonConvert.SerializeObject(updateRequest);
await client.PostAsync(url, data);
}
}
FYI: Async without return is not a good practice. However, it is out of the original question.
If you want to transform an object into a JSON string, see this question: Turn C# object into a JSON string in .NET 4
var json = new JavaScriptSerializer().Serialize(obj);
Is this what you are after or do you want to know how to construct the http request with a JSON object in the body?
your questionis not very clear, what is the outcome that you expect ?
If you want to POST an request with JSON body you can check the #Win comment,
however if you want to make an Response from the Api to the MVC project you should do a bit more steps tough. :))

Deserialize Web Api OData response

I have an Entity Framework object returned by OData V4 controller.
I return an IQueryable and if I call the OData endpoint without any OData clause I can succesfully do this:
var content = response.Content.ReadAsAsync<IQueryable<Person>>();
And the response in JSON is the following:
{
"#odata.context":"http://xxx:8082/odata/$metadata#Persons","value":[
{
"Id":"291b9f1c-2587-4a35-993e-00033a81f6d5",
"Active":true,
"Alert":"Some alerts for the Person",
"Comments":"Some comments for the Person"
}
]
}
But as soon as I start to play with OData, for example by using $expand on a Complex property I get the following exception:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Linq.IQueryable`1[xxx.Person]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
And the response is the following:
{
"#odata.context":"http://aqavnext01:8082/odata/$metadata#Persons","value":[
{
"Id":"291b9f1c-2587-4a35-993e-00033a81f6d5",
"Active":true,
"Alert":"Some alerts for the Person",
"Comments":"Some comments for the Person",
"Party":{
"Id":"291b9f1c-2587-4a35-993e-00033a81f6d5"
}
}
]
}
And I am deserializing using the same object returned by my Web Api so I don't understand why it fails.
Same issue when I apply $select.
Try deserialize the content like this:
var content = response.Content.ReadAsAsync<ODataResponse<Person>>();
Where ODataResponse is:
internal class ODataResponse<T>
{
public T[] Value { get; set; }
}
If you need access to the #odata.xxx fields in the response JSON (such as implementing a loop for paged results), the following is my implementation which expands on the solution from andygjp.
I'm using RestSharp as my HTTP client and Json.NET for (de)serialization. Steps as follows.
Implement a custom IRestSerializer that uses Json.NET to replace the default RestSharp serializer. Below example implementation:
public class JsonNetSerializer : IRestSerializer
{
private readonly JsonSerializerSettings _settings;
public JsonNetSerializer()
{
_settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
_settings.Converters.Add(new StringEnumConverter());
}
public string Serialize(Parameter parameter) => JsonConvert.SerializeObject(parameter.Value, Formatting.None, _settings);
public string Serialize(object obj) => JsonConvert.SerializeObject(obj, Formatting.None, _settings);
public T Deserialize<T>(IRestResponse response) => JsonConvert.DeserializeObject<T>(response.Content);
public string[] SupportedContentTypes => new string[] { "application/json", "text/json", "text/x-json", "text/javascript", "*+json" };
public DataFormat DataFormat => DataFormat.Json;
public string ContentType { get; set; } = "application/json";
}
Next, define a class that will represent your OData responses. My expanded response class - which includes the #odata.nextLink field - looks as follows.
private class ODataResponse<T>
{
public T[] Value { get; set; }
[JsonProperty("#odata.nextLink")]
public string NextLink { get; set; }
}
Finally, I create an instance of RestClient, setting up the custom serializer previously created:
var client = new RestClient("https://base.url.here/")
.UseSerializer(() => new JsonNetSerializer());
Now when I execute my request, the data in the response object object also contains my OData values.
var response = await client.ExecuteAsync<T>(request);
var nextLink = response.Data.NextLink;
I'm sure this can be done using the standard HttpClient instead of RestSharp, as the real work is done by the serializer. This was just the example implementation I had on hand.

How to correctly deserialise JSONArrays using RestSharp

How do I correctly deserialise the results of this call (you can click to see output):
https://bitpay.com/api/rates
I'm using a POCO object like this:
public class BitpayPrice
{
public string code { get; set; }
public string name { get; set; }
public double rate { get; set; }
}
And I'm calling the API like so:
var client = new RestClient();
client.BaseUrl = "https://bitpay.com";
var request = new RestRequest("/api/rates", Method.GET);
var response = client.Execute<BitpayPrice[]>(request);
Now, I know that the call to execute is wrong, but how do I un-wrongify it? I'd like to get back an array of BitcoinPrice objects.
RestSharp doesn't support deserializing into array, the best you can get is a List<>:
var response = client.Execute<List<BitpayPrice>>(request);
The reason is that types that you can deserialize to are required to have public parameterless constructor (for performance reasons mostly).

RestSharp: Converting results

I get the following JSON that I am trying to convert to a business object using RestSharp
{
"valid":true,
"data":[
{
"dealerId":"4373",
"branchId":"4373",
}
]
}
I wish to convert to:
public class Dealer
{
public string dealerId ;
public string branchId;
}
But this fails, though the JSON is fine:
var client = new RestClient("http://www.????.com.au");
var request = new RestRequest(string.Format("service/autocomplete/dealer/{0}/{1}.json", suburb.PostCode, suburb.City.Trim().Replace(" ", "%20")), Method.GET);
var response2 = client.Execute<Dealer>(request);
return response2.Data;
Your business object doesn't match the response JSON you are getting back. If you want your response to serialize, your C# object would look something like
public class DealerResponse
{
public bool valid { get;set; }
List<Dealer> data { get;set; }
}
public class Dealer
{
public string dealerId;
public string branchId;
}
I haven't tested this code, but even though you are only interested in the information in 'data', your response C# objects still need to represent the whole JSON response to serialize correctly.
Hope that helps.

Categories