JSON can not be deserialized - c#

I have made an API request which fetches data from an API. When I look at the JSON I get, it contains the data I need. However, when I try to deserialize the JSON, it does not work.
JSON:
{
"get":"leagues",
"parameters":[
],
"errors":[
],
"results":960,
"paging":{
"current":1,
"total":1
},
"response":[
{
"league":{
"id":4,
"name":"Euro Championship",
"type":"Cup",
"logo":"https:\/\/media-3.api-sports.io\/football\/leagues\/4.png"
},
"country":{
"name":"World",
"code":null,
"flag":null
},
"seasons":[
{
"year":2008,
"start":"2008-06-07",
"end":"2008-06-29",
"current":false,
"coverage":{
"fixtures":{
"events":true,
"lineups":true,
"statistics_fixtures":false,
"statistics_players":false
},
"standings":false,
"players":false,
"top_scorers":false,
"top_assists":false,
"top_cards":false,
"injuries":false,
"predictions":true,
"odds":false
}
},
{
"year":2012,
"start":"2012-06-08",
"end":"2012-07-01",
"current":false,
"coverage":{
"fixtures":{
"events":true,
"lineups":true,
"statistics_fixtures":false,
"statistics_players":false
},
"standings":false,
"players":false,
"top_scorers":false,
"top_assists":false,
"top_cards":false,
"injuries":false,
"predictions":true,
"odds":false
}
},
{
"year":2016,
"start":"2016-06-10",
"end":"2016-07-10",
"current":false,
"coverage":{
"fixtures":{
"events":true,
"lineups":true,
"statistics_fixtures":true,
"statistics_players":true
},
"standings":true,
"players":false,
"top_scorers":false,
"top_assists":false,
"top_cards":false,
"injuries":false,
"predictions":true,
"odds":false
}
},
{
"year":2020,
"start":"2019-03-21",
"end":"2021-07-11",
"current":true,
"coverage":{
"fixtures":{
"events":true,
"lineups":true,
"statistics_fixtures":true,
"statistics_players":true
},
"standings":true,
"players":true,
"top_scorers":true,
"top_assists":true,
"top_cards":true,
"injuries":false,
"predictions":true,
"odds":false
}
}
]
},
Request:
public class LeagueService : ILeagueService
{
public async Task GetLeaguesFromApiAsync()
{
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("-"),
Headers =
{
{ "X-RapidAPI-Key", "-" },
{ "X-RapidAPI-Host", "-" },
}};
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<Root>(body);
}
}
Root class:
public class Root
{
public string Get { get; set; }
public List<object> Parameters { get; set; }
public List<object> Errors { get; set; }
public int Results { get; set; }
public Paging Paging { get; set; }
public List<Response> Response { get; set; }
}
I have checked if the API returns values and it does. However, after deserialization all values in the result are null.

Related

Send Correct Data Fetched to my Model via API

When I fetch data from my Basket API to further on post to my OrderLine API I get this back in JSON:
[
{
"productId": 1,
"quantity": 1
}
]
but my OrderLine API accepts the following:
{
"productId": 0,
"quantity": 0
}
I want to send the data fetched from my Basket API to my OrderLine so that the following is returned:
{
"orderID": 0,
"identifier": "string",
"customer": "string",
"items": [
{
"id": 0,
"productId": 0,
"quantity": 0
}
]
}
Where "items" is the data fetched from my Basket.
This is what my API GET Basket looks like for fetching data from basket:
// GET: https://localhost:5500/api/Basket/{identifier}
[HttpGet("/basket/{identifier}")]
public async Task<IEnumerable<OrderLineDTO>> GetBasketItems(string identifier)
{
var httpRequestMessage = new HttpRequestMessage(
HttpMethod.Get,
$"https://localhost:5500/api/Basket/{identifier}")
{
Headers = { { HeaderNames.Accept, "application/json" }, }
};
var httpClient = httpClientFactory.CreateClient();
using var httpResponseMessage =
await httpClient.SendAsync(httpRequestMessage);
var items = Enumerable.Empty<OrderLineDTO>();
if (!httpResponseMessage.IsSuccessStatusCode)
return items;
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var basketDto = await System.Text.Json.JsonSerializer.DeserializeAsync
<OrderDTO>(contentStream, options);
items = basketDto.Items.Select(x =>
new OrderLineDTO
{
ProductId = x.ProductId,
Quantity = x.Quantity,
}
);
var entryJson = new StringContent(
JsonSerializer.Serialize(items),
Encoding.UTF8,
Application.Json);
await httpClient.PostAsync($"http://localhost:5700/api/OrderLine", entryJson);
return items; // 200 OK
}
And this is my Post to OrderLine:
// POST: api/OrderLine
[HttpPost("/api/OrderLine")]
public async Task<ActionResult<Order>> PostOrderLine(OrderLine orderLine)
{
_context.OrderLine.Add(orderLine);
await _context.SaveChangesAsync();
return CreatedAtAction("GetOrder", new { id = orderLine.Id }, orderLine);
}
This is my OrderLineDTO:
public class OrderLineDTO
{
public int ProductId { get; set; }
public int Quantity { get; set; }
}
And this is my OrderLine model:
public class OrderLine
{
public int Id { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
}
Does anybody know how to solve this? Thanks in advance for any help, I'm just hoping to get the corresponding fetched data from my Basket API then send in back to OrderLine
EDIT:
Also added my OrderDTO which is callled upon in my GET Basket Method:
public class OrderDTO
{
public string Identifier { get; set; }
public string Customer { get; set; }
public List<OrderLine> Items { get; set; } = new List<OrderLine>();
}
You are returning items which is an object of type OrderLineDTO
What you want to return is an object of type OrderDTO

Returning Array of response from Web API C#

I am trying to create a web API which calls the other service and returns a array of response. The called service returns the response. I am able to get the individual item from the called service. But not sure how to build array of items and return as response from the API I am creating.
The JSON returned from the service looks like
{
"cr_response": {
"details": [{
"name": "Req",
"fields": [{
"value": "Prj0\r\nPrj1",
"name": "Project"
},
{
"value": "October 13, 2017 14:18",
"name": "Submitted"
},
{
"value": "John",
"name": "Rec Name"
}
]
}],
"cr_metadata": {}
}
}
And the POCO class looks like
public class Field
{
public string value { get; set; }
public string name { get; set; }
}
public class Detail
{
public string name { get; set; }
public List<Field> fields { get; set; }
}
public class CrMetadata
{
}
public class CrResponse
{
public List<Detail> details { get; set; }
public CrMetadata cr_metadata { get; set; }
}
public class RootObject
{
public CrResponse cr_response { get; set; }
}
Below is the code for calling the service and retrieving the response from the services
var response = await iLab_client.GetAsync(uri);
var datafile = await response.Content.ReadAsStringAsync();
var returnDataObj = JsonConvert.DeserializeObject<DTO.RootObject>(datafile);
foreach (var form in returnDataObj.cr_response.details)
{
name_response = form.name;
return Ok(name_response);
}
Here I can access the name from the details but not sure how can I access the all the name and value from the fields and construct it in a array. And send it as a JSON response.
I tried like
foreach (var form in returnDataObj.cr_response.details)
{
var id_response = form.fields;
return Ok(id_response);
}
But it throws error like
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content
type 'application/xml; charset=utf-8'.
</ExceptionMessage>
System.InvalidOperationException
To return array from Web API you need to fill your array and return it outside foreach loop:
var list = new List<string>();
foreach (...){
var name = ...
list.Add(name);
}
return Ok(list.ToArray()); // or just return Ok(list);
This is how to deserialize JSON to POCO and get the list of the names:
[TestMethod]
public void TestJsonToPocoAndGetNames()
{
const string Json = #"
{
""cr_response"": {
""details"": [{
""name"": ""Req"",
""fields"": [{
""value"": ""Prj0\r\nPrj1"",
""name"": ""Project""
},
{
""value"": ""October 13, 2017 14:18"",
""name"": ""Submitted""
},
{
""value"": ""John"",
""name"": ""Rec Name""
}
]
}],
""cr_metadata"": {}
}
}
";
var settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
var response = JsonConvert.DeserializeObject<RootJsonObject>(Json, settings);
var names = new List<string>();
foreach (var detail in response.CrResponse.Details)
{
names.Add(detail.Name);
foreach (var field in detail.Fields)
{
names.Add(field.Name);
}
}
Assert.AreEqual(
"Req, Project, Submitted, Rec Name",
string.Join(", ", names.ToArray()));
}
POCO classes:
public class RootJsonObject
{
[JsonProperty("cr_response")]
public CrResponse CrResponse { get; set; }
}
public class CrResponse
{
[JsonProperty("cr_metadata")]
public CrMetadata CrMetadata { get; set; }
[JsonProperty("details")]
public Detail[] Details { get; set; }
}
public class CrMetadata
{
}
public class Detail
{
[JsonProperty("fields")]
public Field[] Fields { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class Field
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}

How to get only "intent" field from LUIS returned JSON result using C#

how do I get only the "intent" field from the JSON format code from LUIS return result in C#?
I have already done deserialization like this:
public class ResponseContent
{
[BsonId]
public string query { get; set; }
public string topScoringIntent { get; set; }
public string intent { get; set; }
public string entities { get; set; }
}
public class topScoringIntent
{
public string intent { get; set; }
public string score { get; set; }
}
And this is the LUIS return result:
"query": "Hello.",
"topScoringIntent":
{
"intent": "Greeting",
"score": 0.9447609
},
"intents":
[
{
"intent": "Greeting",
"score": 0.9447609
},
{
"intent": "Request",
"score": 0.09726282
},
{
"intent": "None",
"score": 5.523394E-10
}
],
"entities": []
And I only want the "intent" field from the "TopScoringIntent". How can I get that using C#? Below is the code that I tried but nothing came out:
var uri = "https://southeastasia.api.cognitive.microsoft.com/luis/v2.0/apps/" + luisAppId + "?" + queryString;
var response = await client.GetAsync(uri);
var responseContent = await response.Content.ReadAsStringAsync();
var responseitem = JsonConvert.SerializeObject(responseContent,Formatting.Indented);
JToken content = JToken.Parse(responseitem);
var intentOnly = (from s in content.Children()["ResponseContent"]select s).ToList();
foreach (var item in intentOnly.Children().ToList())
{
Console.WriteLine(item.ToObject<ResponseContent>().TopScoringIntent);
}
This is not a bot so I am not using any bot framework to do this.
Thank you.
Get it done by using the following code:
var jsonresponse = JObject.Parse(responseContent);
intentonly = jsonresponse.SelectToken("intents[0].intent").ToString();

Parsing Dynamic Json datastructure to object C# / dotnet core

I am trying to parse data from Riot API to C# objects
https://developer.riotgames.com/api-methods/#lol-static-data-v1.2/GET_getChampionList
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("https://global.api.riotgames.com/api/lol/static-data/EUW/v1.2/champion?champData=allytips%2Cenemytips%2Cimage%2Ctags&dataById=true&api_key=###################");
if (response.IsSuccessStatusCode)
{
var streamTask = response.Content.ReadAsStreamAsync();
var stringJson = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(ChampionWrapper));
var champions = serializer.ReadObject(await streamTask) as ChampionWrapper;
}
So far I am only getting the type and version converted.
The Data structure looks as following:
{
"type": "champion",
"version": "7.9.1",
"data": {
"89": {
"id": 89,
"key": "Leona",
"name": "Leona",
"title": "the Radiant Dawn",
"image": {
"full": "Leona.png",
"sprite": "champion2.png",
"group": "champion",
"x": 0,
"y": 0,
"w": 48,
"h": 48
},
"allytips": [
"Lead the charge and mark your foes with Sunlight before your allies deal damage.",
"Shield of Daybreak and Zenith Blade form a powerful offensive combo.",
"You can absorb a huge amount of damage using Eclipse, but you must stay near enemies to gain the bonus duration."
],
"enemytips": [
"When Leona activates Eclipse, you have three seconds to get away from her before she deals damage.",
"Only foes in the center of Solar Flare get stunned, so you can often avoid this if you're quick."
],
"tags": [
"Tank",
"Support"
]
},
"110": {
"id": 110,
"key": "Varus",
"name": "Varus",
"title": "the Arrow of Retribution",
"image": {
"full": "Varus.png",
"sprite": "champion3.png",
"group": "champion",
"x": 336,
"y": 96,
"w": 48,
"h": 48
},
So far I have a ChampionWrapper:
public class ChampionWrapper
{
public string type { get; set; }
public string version { get; set; }
public List<ChampionData> data { get; set; }
public ChampionWrapper()
{
}
}
List ChampionData is not getting populated. Version and type is working.
public List<string> id {get;set;}
public List<Champion> id { get; set; }
public ChampionData()
{
}
Here is the champion object
public string Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public List<string> AllyTips { get; set; }
public List<string> EnemyTips { get; set; }
public List<string> Tags { get; set; }
public Champion()
{
}
My main problem is the dynamic datastruce
"data": {
"89": { .... }
"110": { .... }
The number is just the ID of the champion.
Found solution:
DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
The whole thing:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("https://global.api.riotgames.com/api/lol/static-data/EUW/v1.2/champion?champData=allytips%2Cenemytips%2Cimage%2Ctags&dataById=true&api_key=###########");
if (response.IsSuccessStatusCode)
{
DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
var streamTask = response.Content.ReadAsStreamAsync();
var stringJson = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(ChampionWrapper), settings);
var champions = serializer.ReadObject(await streamTask) as ChampionWrapper;
}
And ofcourse changing list to Dictionary:
public class ChampionWrapper
{
public string type { get; set; }
public string version { get; set; }
public Dictionary<string, Champion> data { get; set; }
}
You are not using the correct class for deserializing your object. The data property in your json is not a List, but more like a Dictionary:
public class ChampionWrapper
{
public string type { get; set; }
public string version { get; set; }
public Dictionary<string, Champion> data { get; set; }
}
[Edit]
I believe that you are complicating the way to deserialize the response from Json, instead of deserializing the response manually using DataContractSerializer you should use ReadAsAsync<T> extension method to obtain an object of your class:
if(response.IsSuccessStatusCode)
{
var champions = await response.Content.ReadAsAsync<ChampionWrapper>();
}
This extension method is found inside the Microsoft.AspNet.WebApi.Client nuget package, remember to add it before using it.

Build JSON response in Web API controller

In a WebAPI project, i have a controller that checks a status of a product, based on a value the user enters.
Lets say they enter "123" and the response should be "status": 1, AND a list of products. If they enter "321" the "status" is 0, AND a list of products.
My question is, how do i build such a string correct in a WebAPI controller.
[Route("{value:int}")]
public string GetProducts(int value)
{
var json = "";
var products = db.Products;
if (products.Any())
{
foreach (var s in products)
{
ProductApi product = new ProductApi();
product.Name = s.Name;
json += JsonConvert.SerializeObject(supplier);
}
}
var status = db.Status;
if (status.Any())
{
json += "{status:1}";
}
else
{
json += "{status:0}";
}
return json;
}
public class ProductApi
{
public string Name { get; set; }
}
Also, is this output/response considered valid?
[
{
"id":1,
"name":"product name"
},
{
"id":2,
"name":"product name 2"
},
{
"id":3,
"name":"product name 3"
}
]
{
"status": 0
}
So here are the changes for your post:
First, you should make your api return Json by default when you pass a text/html request (is this you are looking for?), adding this line to your WebApiConfig class:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Second, I changed the code to return a real object, impersonating your response:
public class ProductApiCollection
{
public ProductApi[] Products { get; set; }
public byte Status { get; set; }
}
public class ProductApi
{
public string Name { get; set; }
}
Method body:
public ProductApiCollection Get()
{
var result = new ProductApiCollection();
var dbProducts = db.Products;
var apiModels = dbProducts.Select(x => new ProductApi { Name = x.Name } ).ToArray();
result.Products = apiModels;
var status = db.Status.Any() ? 1 : 0;
result.Status = status;
return result;
}
This will results in the following example json:
{
"Products": [
{
"Name": "Pork"
},
{
"Name": "Beef"
},
{
"Name": "Chicken"
},
{
"Name": "Salad"
}
],
"Status": 1
}
I strongly advise you not to do manual formatting for such things, and rely on built-in and 3rd party libraries. Otherwise, you will be reinventing the things already available, tested and ready to work.
Just as raderick mentioned, you don't need to create your own custom JSON infrastructure.
public class ProductApi
{
public int Id {get;set;}
public string Name { get; set; }
}
public class ResponseDTO
{
public int Status {get;set;}
public List<ProductApi> { get; set; }
}
And in your API action, return like this:
[Route("{value:int}")]
public ResponseDTO GetProducts(int value)
{
ResponseDTO result = ...// construct response here
return result;
}

Categories

Resources