Connecting to REST Api and retrieving JSON - c#

I am connecting to an API, but not having any luck retrieving the data in Json. I have different endpoints to use, but cant seem the any to work. I believe /products should give me the entire list but am having no luck.
class Program
{
static void Main(string[] args)
{
RunAsync().Wait();
}
static async Task RunAsync()
{
using (var client = new HttpClient())
{
//go get the data
string token = "auth token";
client.BaseAddress = new Uri("");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Console.WriteLine("GET");
HttpResponseMessage response = await client.GetAsync("/products/6");
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Connected");
RootObject product = await response.Content.ReadAsAsync<RootObject>();
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", product.data.id,product.data.name,product.data.sort,product.data.designation_id,product.data.designation_id);
}
else
{
Console.WriteLine("Failed");
Console.WriteLine(response.Headers);
}
}
}
}
The response I am getting in the console on this is:
0
1/1/0001 12:00:00 AM
1/1/0001 12:00:00 AM
Product class:
public class RootObject
{
public Product data { get; set; }
}
public class Product
{
public int id { get; set; }
public object designation_id { get; set; }
public string name { get; set; }
public object alternate_name { get; set; }
public object description { get; set; }
public int sort { get; set; }
public string created_at { get; set; }
public string updated_at { get; set; }
}
The response I get when testing connection with postman is as follows:
{
"data": {
"id": 6,
"designation_id": null,
"name": "Multirate Fork Springs Kit",
"alternate_name": null,
"description": null,
"sort": 0,
"created_at": "2016-06-17 20:47:51",
"updated_at": "2018-05-25 09:40:50"
}
}

nuget Newtonsoft.Json
and you can do something like this:
using Newtonsoft.Json;
in client, using response
Product product = JsonConvert.DeserializeObject<Product>(your response string);
this works really well, as long as your product class has all the right attributes you should be good to go!

Related

C# Accessing APIs

I followed a tutorial (https://www.youtube.com/watch?v=aWePkE2ReGw) to try and call APIs using C#, and while it worked, my attempts to modify it for my own projects failed miserably. Despite my best efforts and trying various different links on the same website, they all return failure.
I was able to access it with python no problem, so the problem seems confined to C#. I have the microsoft.aspnet.webapi.client installed, as well as json. It compiles and runs, just returns failure.
https://dbd.tricky.lol/apidocs/
Here's the code:
namespace API_Test
{
// class used to initialize the httpclient
public class ApiHelper
{
public static HttpClient? ApiClient { get; set; }
public static void InitializeClient()
{
ApiClient = new HttpClient();
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}
}
// used to hold the result
class ShrineModel
{
public double ID { get; set; }
}
// used for processing results
class ShrineResultModel
{
public ShrineModel? Results { get; set; }
}
// used to access the api
class ShrineProcessor
{
public static async Task<ShrineModel> LoadShrineInformation()
{
string url = "https://dbd.tricky.lol/api/shrine";
using (HttpResponseMessage response = await ApiHelper.ApiClient.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
ShrineResultModel result = await response.Content.ReadAsAsync<ShrineResultModel>();
return result.Results;
}
else
{
// ALWAYS ENDS UP HERE
Console.WriteLine("Failure");
Console.ReadKey();
throw new Exception(response.ReasonPhrase);
}
}
}
}
// main
public class API_Test
{
static async Task Main()
{
ApiHelper.InitializeClient();
var ShrineInfo = await ShrineProcessor.LoadShrineInformation();
Console.WriteLine(ShrineInfo.ID);
}
}
}
Best case scenario I get a json output with all the information found at the link. What I'm getting is a false response from "IsSuccessStatusCode"
I've tried various other endpoints available from the same website. Other APIs have worked. But I can't get this one to.
I ran your code against the API and there are a couple of issues to fix.
1. 403 Forbidden
You got response.IsSuccessStatusCode false because the API endpoint requires a User-Agent header. This is to block any web crawler bots.
To fix that you just need to add this code,
ApiClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0");
2. Wrong JSON data model
You must model the JSON response structure so the deserialization can work properly.
The JSON response:
{
"id": 666,
"perks": [
{
"id": "Aftercare",
"bloodpoints": 100000,
"shards": 2000
},
{
"id": "BeastOfPrey",
"bloodpoints": 100000,
"shards": 2000
},
{
"id": "DeadHard",
"bloodpoints": 100000,
"shards": 2000
},
{
"id": "Nemesis",
"bloodpoints": 100000,
"shards": 2000
}
],
"start": 1672185600,
"end": 1672790399
}
So your ShrineResultModel should be like this:
public class Perk
{
public string id { get; set; }
public int bloodpoints { get; set; }
public int shards { get; set; }
}
public class ShrineResultModel
{
public int id { get; set; }
public List<Perk> perks { get; set; }
public int start { get; set; }
public int end { get; set; }
}
Update your code to deserialize the JSON response:
if (response.IsSuccessStatusCode)
{
ShrineResultModel result = await response.Content.ReadFromJsonAsync<ShrineResultModel>();
return result;
}
The actual result:

How can I convert url-encoded or url-decoded string to json format and then to object?

I'm getting a post request to my api (x-www-form-urlencoded) and the body of the request looks like this:
worker=%7B%22_id%22%3A+%7B%22%24oid%22%3A+%2261asd23e9231241dfd2b4c3bd%22%7D%2C+%22sid%22%3A+%22WKb32df49cas43413585352e8a6e2%cd%22%22%%22%3A+1234154123%7D%7D&task=%7B%22_id%22%3A+%7B%22%24oid%22%3A+%2261caffc34dsf33182b4c789
continues.
There are 2 objects (classes) that I need to receive in this incoming request, and I created the class structure of these 2 objects: For example, my class structure is as follows:
public class Worker
{
[JsonProperty("friendly_name")]
public string FriendlyName { get; set; }
[JsonProperty("date_updated")]
public WorkerDateUpdated DateUpdated { get; set; }
[JsonProperty("activity")]
public string Activity { get; set; }
[JsonProperty("workspace_sid")]
public string WorkspaceSid { get; set; }
[JsonProperty("date_created")]
public WorkerDateCreated DateCreated { get; set; }
[JsonProperty("queues")]
public List<string> queues { get; set; }
}
public class Task
{
[JsonProperty("reason")]
public string Reason { get; set; }
[JsonProperty("date_updated")]
public TaskDateUpdated DateUpdated { get; }
[JsonProperty("assignment_status")]
public string AssignmentStatus { get; set; }
[JsonProperty("total_cost")]
public TaskTotalCost TotalCost { get; set; }
}
In the incoming request, I receive 3 objects (class) as url-encoded, I only need 2 objects and their properties.
using (var reader = new StreamReader(
HttpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
_logger.LogInformation("BodyString ---> " + bodyString);
var decodedUrl = HttpUtility.UrlDecode(bodyString);
_logger.LogInformation(" decodedUrl ---> " + decodedUrl);
}
I can read the incoming body and convert it to decoded format. Below is an example:
worker={"_id": {"$oid": "XXXXXXXXXX"}, "sid": "XXXXXXXXXXXXX", "x": true, "account_sid": "XXXXXXXXXXXX", "workspace_sid": "XXXXXXXXXXXX", "queues ": ["XXXXXXXXXXXXXX"], "activity": "idle", "available": true, "friendly_name": "XXXXXXXX", "attributes": {"mail": "XXXXXXXXXXXX", "name": "XXXXXXXXXX" }, "date_created": {"$date": XXXXXXXXX}, "date_updated": {"$date": XXXXXXXXXX}, "date_status_changed": {"$date": XXXXXXXXXXXXX}}&task={"_id": {" $oid": "XXXXXXXXXXXXXX"}, "sid": "XXXXXXXXXXXX", "x": true, "account_sid": "XXXXXXXXXXX", "workspace_sid": "XXXXXXXXXXXXXXXXXX", "workflow_sid": "XXXXXXXXXXXX", "workflow_friendly_name" : "daytime1", "initial_attributes": {"station_name": "XXXXX", "component_type": X, "component_id": XXX, "mail": "XXXXXX", "main_issue": "XXXXXXXXXXXXXX", "predictivi_maintenance_time": "XXXXXXXXXX", "hospital_name": "\u00dcsk\u00fcdar XXXXXXXXXXX"}
I can see it as , but I can't deserialize it. Or I don't know if I'm doing it wrong. I have created a separate class that contains my 2 classes. I keep my Worker and Task class in it, I cannot deserialize to that class, it does not deserialize in any way. Unexpected charachter throws exception. How can I convert these objects to json format or object format?
Edit:
My Other Custom classes:
public class TaskDateUpdated
{
[JsonProperty("$date")]
public long Date { get; set; }
}
public class TaskTotalCost
{
[JsonProperty("$numberDecimal")]
public string NumberDecimal { get; set; }
}
public class TaskDateCreated
{
[JsonProperty("$date")]
public long Date { get; set; }
}
public class TaskLastChargeDate
{
[JsonProperty("$date")]
public long Date { get; set; }
}
public class TaskId
{
[JsonProperty("$oid")]
public string Oid { get; set; }
}
public class WorkerDateUpdated
{
[JsonProperty("$date")]
public long date { get; set; }
}
public class WorkerDateCreated
{
[JsonProperty("$date")]
public long date { get; set; }
}
public class WorkerDateStatusChanged
{
[JsonProperty("$date")]
public long date { get; set; }
}
I also have a single class containing these 2 classes, I get an error when I try to deserialize to this class, I also get an error when I try to deserialize it to other worker and task classes separately. I can't deserialize at all.
public class DataContainer
{
public Task Task { get; set; }
public Worker Worker { get; set; }
}
My post method looks like this:
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<ActionResult<ResponseRequest>> AddWorkerTask()
{
using (var reader = new StreamReader(
HttpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
_logger.LogInformation("BodyString ---> " + bodyString);
var decoded = HttpUtility.UrlDecode(bodyString);
//here is where i need to deserialize and convert it to
//a valid json and object
}
}
You can use HttpUtility.ParseQueryString to parse it into a NameValueCollection, then simply use the indexer ["worker"] on that.
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<ActionResult<ResponseRequest>> AddWorkerTask()
{
using (var reader = new StreamReader(
HttpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
var decoded = HttpUtility.ParseQueryString(bodyString);
var worker = JsonSerializer.Deserialize<Worker>(decoded["worker"]);
var task = JsonSerializer.Deserialize<Task>(decoded["task"]);
// or whatever your JSON deserializer is
}
}
In newer versions of ASP.net Core you can use HttpContext.Request.Form
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<ActionResult<ResponseRequest>> AddWorkerTask()
{
var worker = JsonSerializer.Deserialize<Worker>(HttpContext.Request.Form["worker"]);
var task = JsonSerializer.Deserialize<Task>(HttpContext.Request.Form["task"]); // or whatever your JSON deserializer is
}

My xamarin app freezes when i try JsonConvert.DeserializeObject <T>

When I get a json response from HttpClient () and try to deselize, my Xamarin application freezes (UI works, but the code after in class ExecuteGetRequest line 15 does not work). What can it be because of?
No errors.
I call the method of obtaining a list of anime user
ShikimoriMain shikimoriMain = new ShikimoriMain();
var UserInformation = await shikimoriMain.GetUserInformation(Convert.ToInt64(UserID));
var UserAnimeList = await shikimoriMain.GetUserAnimeList(Convert.ToInt64(UserID), 1, 5);
string animeName = UserAnimeList.Anime[0].Anime.Name;
ShikimoriMain.GetUserAnimeList
public async Task<ShikimoriUserAnimeList> GetUserAnimeList(long id, int page, int limit)
{
string[] args = new string[] { ShikimoriCategories.UserID + "/" + id + ShikimoriCategories.UserAnimeList + $"?limit={limit}&page={page}" };
return await ExecuteGetRequest<ShikimoriUserAnimeList>(args);
}
ExecuteGetRequest
public async Task<T> ExecuteGetRequest<T>(string[] args) where T : class
{
T returnedObject;
using (var client = new HttpClient())
{
// client.BaseAddress = new Uri($"{httpApiv1}/{args}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, httpApiv1 + String.Join("/", args));
request.Headers.TryAddWithoutValidation("User-Agent", "Search Anime");
HttpResponseMessage responseMessage = await client.SendAsync(request);
string json = await responseMessage.Content.ReadAsStringAsync(); // successfully get json
returnedObject = JsonConvert.DeserializeObject<T>(json); // after that the code is not executed
return returnedObject;
}
}
ShikimoriUserAnimeList
public class ShikimoriUserAnimeList
{
[JsonProperty()]
public List<GetAnime> Anime { get; set; }
}
public class GetAnime
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("anime")]
public Anime Anime { get; set; }
}
public class Anime
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("russian")]
public string NameRU { get; set; }
[JsonProperty("image")]
public AnimeImage AnimeImage { get; set; }
[JsonProperty("kind")]
public string King { get; set; }
[JsonProperty("score")]
public string Score { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("episodes")]
public int Episodes { get; set; }
}
public class AnimeImage
{
[JsonProperty("original")]
public string Original { get; set; }
[JsonProperty("preview")]
public string Preview { get; set; }
[JsonProperty("x96")]
public string ImageX96 { get; set; }
[JsonProperty("x48")]
public string ImageX48 { get; set; }
}
For the sake of completion:
An error was being thrown but was not visible in the device log. Wrapping the JsonConvert.DeserializeObject<T>(json) in a try catch block helped finding the Exceptionbeing thrown.
try
{
returnedObject = JsonConvert.DeserializeObject<T>(json); // after that the code is not executed
return returnedObject;
}
catch (Exception ex)
{
... (debug and fix the error that occurred)
}
I had same problem, I've realized that using HttpClient async will cause deadlock in winforms or xamarin (however it works well with Asp) and I changed these lines
HttpResponseMessage responseMessage = await client.SendAsync(request);
string json = await responseMessage.Content.ReadAsStringAsync(); // successfully get json
Like these (Make them work synchronous):
HttpResponseMessage responseMessage = client.SendAsync(request).Result;
string json = responseMessage.Content.ReadAsStringAsync().Result; // successfully get json
And change your method as default synchronous
Take a look at Here

RestSharp - GET request with "$" response attribute name

I need to get GET response from REST API. I use RestSharp. The problem is, that one name of the response attribute is "$". This is the response:
[
{
"CodeId": {
"$": "00000000"
},
"Entity": {
"LegalName": {
"#xml:lang": "cs",
"$": "xxxxx"
}
}
}
]
How should I use the RestSharp to get the value of Entity.LegalName.$ ?
I found the answer thanks by #fredrik.
var client = new RestClient(url);
var request = new RestRequest(urlRequest, DataFormat.Json);
var response = client.Get(request);
Console.WriteLine(JsonSerializer.Deserialize<List<TestRestResponseTemplate>>(response.Content)[0].Entity.LegalName.Value);
TestRestResponseTemplate:
public class TestRestResponseTemplate
{
public Entity Entity { get; set; }
}
public class LegalName
{
[JsonPropertyName("#xml:lang")]
public string Language { get; set; }
[JsonPropertyName("$")]
public string Value { get; set; }
}
public class Entity
{
public LegalName LegalName { get; set; }
}

Deserializing API call to object doesn't work on List

I am trying to call an API with HttpClient and deserialize the json to a response object. In this json, there is a list of trivia question objects. When I set the object to the deserialized object, the list stays empty.
I've checked if HttpClient works, it does, I also tried using JsonConvert.
These are the TriviaQuestion and Response classes:
public class TriviaQuestion
{
public string Category { get; set; }
public string Type { get; set; }
public string Difficulty { get; set; }
public string Question { get; set; }
public string CorrectAnswer { get; set; }
public List<string> IncorrectAnswers { get; set; }
public override string ToString()
{
return $"Question: {Question}";
}
}
public class Response
{
public int ResponseCode { get; set; }
public List<TriviaQuestion> Questions { get; set; }
public Response()
{
Questions = new List<TriviaQuestion>();
}
}
This is the code for deserializing
private static HttpClient client = new HttpClient();
private static string URL = "https://opentdb.com/api.php";
private static string urlParameters = "?amount=1";
static void Main()
{
RunAsync().GetAwaiter().GetResult();
}
static async Task RunAsync()
{
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Response response = new Response();
try
{
response = await GetResponseAsync(urlParameters);
ShowResponse(response);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
static async Task<Response> GetResponseAsync(string path)
{
Response response = new Response();
//string responseString = "";
HttpResponseMessage httpResponse = await client.GetAsync(path);
if (httpResponse.IsSuccessStatusCode)
{
//responseString = httpResponse.Content.ReadAsStringAsync().Result;
response = await httpResponse.Content.ReadAsAsync<Response>();
}
//response = JsonConvert.DeserializeObject<Response>(responseString);
return response;
}
I expect to get a list of trivia question objects, but the list stays on count = 0. If I print out the jsonString I'm getting this is the result:
{
"response_code":0,
"results": [
{
"category":"Entertainment: Video Games",
"type":"multiple",
"difficulty":"medium",
"question":"In Need for Speed: Underground, what car does Eddie drive?",
"correct_answer":"Nissan Skyline GT-R (R34)",
"incorrect_answers": [
"Mazda RX-7 FD3S",
"Acura Integra Type R",
"Subaru Impreza 2.5 RS"
]
}]
}
Thanks for helping!
Your Response class is slightly wrong. It does not match the JSON you posted.
public List<TriviaQuestion> Questions { get; set; }
should be:
public List<TriviaQuestion> Results { get; set; }
Additionally, as your JSON has snake casing, to capture the response_code, correct_answer and incorrect_answers values you will need to either decorate your class properties with JsonProperty attributes i.e. [JsonProperty(PropertyName = "incorrect_answers")] or you can use a ContractResolver:
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
var response = JsonConvert.DeserializeObject<Response>(json, new JsonSerializerSettings
{
ContractResolver = contractResolver
});
So your full classes would be:
public class TriviaQuestion
{
public string Category { get; set; }
public string Type { get; set; }
public string Difficulty { get; set; }
public string Question { get; set; }
// only need this if not using the ContractResolver
[JsonProperty(PropertyName = "correct_answer")]
public string CorrectAnswer { get; set; }
// only need this if not using the ContractResolver
[JsonProperty(PropertyName = "incorrect_answers")]
public List<string> IncorrectAnswers { get; set; }
}
public class Response
{
// only need this if not using the ContractResolver
[JsonProperty(PropertyName = "response_code")]
public int ResponseCode { get; set; }
public List<TriviaQuestion> Results { get; set; }
}
Then you will be able to deserialize:
var json = "{\r\n \"response_code\":0,\r\n \"results\": [\r\n { \r\n \"category\":\"Entertainment: Video Games\",\r\n \"type\":\"multiple\",\r\n \"difficulty\":\"medium\",\r\n \"question\":\"In Need for Speed: Underground, what car does Eddie drive?\",\r\n \"correct_answer\":\"Nissan Skyline GT-R (R34)\",\r\n \"incorrect_answers\": [\r\n \"Mazda RX-7 FD3S\",\r\n \"Acura Integra Type R\",\r\n \"Subaru Impreza 2.5 RS\"\r\n ]\r\n }]\r\n}";
// if using JsonProperty attributes
var response = JsonConvert.DeserializeObject<Response>(json);
// or
// if using ContractResolver
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
var response = JsonConvert.DeserializeObject<Response>(json, new JsonSerializerSettings
{
ContractResolver = contractResolver
});
the returned JSON into a Response:
var json = await httpResponse.Content.ReadAsStringAsync();
response= JsonConvert.DeserializeObject<Response>(json);

Categories

Resources