I have created a basic ASP.Net Web Application and I am trying to use the OpenWeatherMap API with this. (first time dealing with APIs).
The Info I have about the WebAPI is:
You can search weather forecast for 5 days with data every 3 hours by city name. All weather data can be obtained in JSON and XML formats.
There is a possibility to receive a central district of the city/town with its own parameters (geographic coordinates/id/name) in API response. Example
API call:
api.openweathermap.org/data/2.5/forecast?q={city name},{country code}
Parameters:
q city name and country code divided by comma, use ISO 3166 country codes
Examples of API calls:
api.openweathermap.org/data/2.5/forecast?q=London,us&mode=xml
Currently I have this working when I use the api that returns a json object
api.openweathermap.org/data/2.5/weather?q=London&units=metric
However if I simply change the URL to the first (which returns the XML) my application no longer retrieves the data from the API.
I have tried amended the mode=xml into mode=json but still no avail.
How can I use the first web API?
Many thanks
--Edit:
In my model class i have the following method:
string url = "api.openweathermap.org/data/2.5/…;
var client = new WebClient();
var content = client.DownloadString(url);
var serializer = new JavaScriptSerializer();
var jsonContent = serializer.Deserialize<Object>(content);
return jsonContent;
(taken out the key) I then call this method from my view. However I cannot use that api call that has the =xml at the end
your problem is when result is returned as xml, you are using a JavaScriptSerializer to Deserialize it.
xml is not json, hence the Deserialization would have failed
what you need is a XmlSerializer to deserializae the result
below is some code to get you started:
string url = #"http://samples.openweathermap.org/data/2.5/forecast?q=London&appid=b1b15e88fa797225412429c1c50c122a1&mode=xml";
var client = new WebClient();
var content = client.DownloadString(url);
XmlSerializer serializer = new XmlSerializer(typeof(weatherdata));
weatherdata result = null;
using (TextReader reader = new StringReader(content))
{
result = (weatherdata)serializer.Deserialize(reader);
}
notice that typeof weatherdata - it is no point of Deserialize into non strong type object if you are going to deserialize into object,
there is noting you can do with it.
if you don't want to hand code the strong type model, copy the xml result into clipboard then use VS (not sure other version but 2017 as example) toolbar
Edit -> paste special -> Paste xml as classes to generate the strong type class for you
Related
I am receiving a JSON result from this API web page (https://flagrantflop.com/api/endpoint.php?api_key=13b6ca7fa0e3cd29255e044b167b01d7&scope=team_stats&season=2019-2020&season_type=regular&team_name=Atlanta%20Hawks)
Using the RestSharp library, so far I've got this:
var client = new RestClient("https://flagrantflop.com/api/endpoint.php?api_key=13b6ca7fa0e3cd29255e044b167b01d7&scope=team_stats&season=2019-2020&season_type=regular&team_name=");
var request = new RestRequest("Atlanta Hawks", DataFormat.Json);
var response = client.Get(request);
I have tested the URL and the request part that specifies the team and both work.
I know there are a number of methods of deserializing the JSON, however not sure the best way.
The request isn't working because the argument you're supplying in RestRequest is treated as its own page stemming off the base URI.
You can verify that by calling client.BuildUri(request) with your current setup―you'll see that the resolved URL is https://flagrantflop.com/api/Atlanta Hawks, which is why you weren't getting the proper JSON response. I recommend rewriting the request like this, but there are other valid ways:
var client = new RestClient("https://flagrantflop.com/api/")
.AddDefaultQueryParameter("api_key", "13b6ca7fa0e3cd29255e044b167b01d7")
.AddDefaultQueryParameter("scope", "team_stats")
.AddDefaultQueryParameter("season", "2019-2020")
.AddDefaultQueryParameter("season_type", "regular");
var request = new RestRequest("endpoint.php")
.AddQueryParameter("team_name", "Atlanta Hawks");
After that, you can have RestSharp automatically deserialize your response:
RootObject response = client.Get<RootObject>(request);
By default, this uses SimpleJson to deserialize your object.
My Web API, AAA, calls another API, BBB, to retrieve a large JSON array (~500-1000 KB and each object is 10 KB), it needs to parse the JSON array to apply a logic on it and forward the response to API CCC.
For optimization, I'd like that my Web API AAA doesn't have store the HTTP response containing the large JSON array, so the array doesn't have to be stored in the LOH (Large Object Heap).
I think a good idea to solve this issue is: instead of waiting for the full JSON array to be downloaded, is it possible to parse the elements of the response as it arrives so I can parse it, apply a logic on it and forward the content to my API CCC?
So my Web API never gets to store the large JSON array in memory. By parsing each object as it arrives, the object is so small that it will be stored in GEN 0 and gets collected really fast by GC.
What I tried so far:
My API BBB looks like this (simplified):
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var text = System.IO.File.ReadAllText("C:\\Users\\John\\generated1000objects.json");
var deserialized = JsonConvert.DeserializeObject<object[]>(text);
return Ok(deserialized);
}
My code to query
var httpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:44328/api/values/4"))
using (var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
using (Stream stream = await response.Content.ReadAsStreamAsync())
using (StreamReader sr = new StreamReader(stream))
using (JsonReader reader = new JsonTextReader(sr))
{
reader.SupportMultipleContent = true;
while (true)
{
if (!reader.Read())
{
break;
}
JsonSerializer serializer = new JsonSerializer();
var deserialize = serializer.Deserialize<object>(reader);
Console.WriteLine(deserialize); // HERE it prints the whole JSON Array. I was expecting to deal with one object of the array
Console.WriteLine("#################");
}
}
My constraints:
I can't modify the API BBB that send the large JSON array.
My API CCC cannot directly call API BBB to retrieve the large JSON array
I'm on .NET Core with ASP.NET Core 2.2.
Looking at your solution, unless you are expecting this to grow in size substantially I believe that you might be suffering from trying to attempt a micro-optimization that will actually make your process more fragile than by simply processing in a regular manner.
You mention a record size of 10k, a response size of 500-1000k. This translates to a total of 50-100 records.
I believe that you will experience more difficulties in trying to parse the response in chunks than any impact of having an object on the Large Object Heap will provide. From what I can find in the various documentation, the ONLY way to parse a JSON document using a built-in library is to parse the whole document. Any chunking would need to be managed by yourself.
I'm writing an automation test. I've got an endpoint URL 'https://deckofcardsapi.com/api/deck/new/shuffle/?deck_count=1' when I go onto this endpoint there is text that is printed.
Is there any way in my test I can validate some of the data within the text that is printed. For example, validate when I go to the endpoint remaining is 52.
{
"deck_id":"qzpre4zxokj7",
"shuffled":true,
"remaining":52,
"success":true
}
You can use the JSON parser to extract the remaining value.
NuGet Package :
Newtonsoft.Json
I assumed you are getting the below text in your response.So, please use the below code to extract the remaining value
{
"deck_id":"qzpre4zxokj7",
"shuffled":true,
"remaining":52,
"success":true
}
Code:
var expectedValue =52;
var apiResponse = <<Stroe the API Text Response>>;
var jsonObject = JObject.Parse(apiResponse);
var remaining = jsonObject["remaining"].ToString();//It will retrun the value as 52
var actualValue = Int64.Parse(remaining);
Assert.AreEqual(expectedValue, actualValue);//Validate the remaing Value from the API Response
That is likely a "REST" endpoint. When you do a GET from that endpoint, it is returning with "JSON" (JavaScript Object Notation). What you are seeing is an object returned in JSON format. The object has 4 properties (deck_id, shuffled, remaining, and success). The value of "remaining" is 52. Find a JSON parser and you should be able to see this.
If you search the internet, you should find Selenium tools that can parse JSON (sorry, I'm not an expert in that technology).
I have trouble in retrieve data from Json Object from Restful.
Currently, I am using RestSharp to get the response from the api.
Based on what I have studied in Use C# to get JSON Data
I do not quite understand on the data retrieving. If I want to retrieve just a single data from the API,
Can I declared on specific data that I want to retrieve from the api in Model class or I need to declare every parameters from the API?
How do I retrieve only specific data from the API?
If the Api consists of an Object in outter part, how to do get the data in the nested object?
Please enlighten me on this matter. Thank you in advanced.
This is the sample code that I created,
var client = new RestClient(<myAPIkey>);
var request = new RestRequest(String.Format("post", Method.GET));
client.ExecuteAsync(request, response =>
{
Console.WriteLine(response.Content);
});
EDITED
I have edited my project as I am testing to get data from hardcoded Json data as such,
[{"id":"518523721","name":"ftyft"},
{"id":"527032438","name":"ftyftyf"},
{"id":"527572047","name":"ftgft"},
{"id":"531141884","name":"ftftft"}]
With Model class of,
public class TestInfo
{
public string id { get; set; }
public string name { get; set; }
}
and the code for deserialize,
TestInfo curTest = new TestInfo();
curTest = JsonConvert.DeserializeObject<TestInfo>(json1);
Console.WriteLine(curTest.id);
I still failed to get the id and name from the json data as it returns empty in Console.WriteLine. Can you please guide me through on how to read the json data?
Can I declared on specific data that I want to retrieve from the api
in Model class or I need to declare every parameters from the API?
It depends on the way which the api was designed. When you say parameters, are you trying to say routes or end-points? Your question is a little bit confused.
How do I retrieve only specific data from the API?
Can you be more specific? Are you talking about the route which you are trying to retrieve your data?
If the Api consists of an Object in other part, how to do get the
data in the nested object?
You can use Newtonsoft.Json(which is the most popular package in nuget) to deserialize your json object. Also, it will only be possible if you create an C# class which will be a mirror from your json model.
You can use an online tool like https://jsonutils.com/ to create this class automatically.
edit:
Since you are trying to deserialize a list of several objetcs, you should try the following approach:
var json1 =
"[{\"id\":\"518523721\",\"name\":\"ftyft\"},\r\n{\"id\":\"527032438\",\"name\":\"ftyftyf\"},\r\n{\"id\":\"527572047\",\"name\":\"ftgft\"}, \r\n{\"id\":\"531141884\",\"name\":\"ftftft\"}]";
var curTest = JsonConvert.DeserializeObject<List<TestInfo>>(json1);
Console.WriteLine(curTest[0].id);
It will works now.
Use the returned structure and put it on something like http://json2csharp.com/ to get a mapping object. And then you can deserialize it ref:
RootObject obj = new JavaScriptSerializer().Deserialize<RootObject>(response.Content);
//obj.YourDesiredProperty;
I was little late but it works for me.
var request = HttpWebRequest.Create(#"http://peerff.azurewebsites.net/api/team");
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
}
I’ve got 2 projects that run on different servers but both have a reference to a common dll that contains a complex type called LeadVM. LeadVM contains sub-objects, like Employer which contains properties. Ex:
LeadVM.FirstName
LeadVM.LastName
LeadVM.Employer.Name
LeadVM.Employer.Phone
So, project 1 can create a LeadVM type of object, and populate it. I need to then, via an HTTP call, POST in the data to a controller/action in the 2nd project. The 2nd project knows what a LeadVM object is.
How can I...serialize(?) LeadVM and pass it to the accepting Action in the 2nd project?
EDIT: Thanks to #Unicorno Marley, I ended up using the Newtonsoft JSON stuff.
Now I just create my object in project 1, then do the following code (I'm sure it's clunky but it works).
LeadVM NewCustomer = new LeadVM();
NewCustomer.set stuff here....
var js = Newtonsoft.Json.JsonSerializer.Create();
var tx = new StringWriter();
js.Serialize(tx, NewCustomer);
string leadJSON = tx.ToString();
And then I can use HttpWebRequest to send a web request to my project 2.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:1234/Lead/Create");
request.Method = "POST";
StreamWriter streamOut = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
streamOut.Write(System.Web.HttpUtility.UrlEncode(leadJSON));
streamOut.Close();
HttpWebResponse resp = null;
resp = (HttpWebResponse)request.GetResponse();
StreamReader responseReader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8);
sResponse = responseReader.ReadToEnd();
resp.Close();
In project 2, I can catch the json sent like this and my NewCustomer object in project 2 is already populated, ready for use.
var buffer = new byte[Request.InputStream.Length];
Request.InputStream.Read(buffer, 0, buffer.Length);
string json = System.Text.Encoding.Default.GetString(buffer);
json = System.Web.HttpUtility.UrlDecode(json);
LeadVM NewCustomer = Newtonsoft.Json.JsonConvert.DeserializeObject<PhoenixLead.LeadVM>(json);
I'm sure I'm doing things very awkwardly. I'll clean it up, but wanted to post the answer that I was led to.
Json is probably the most common option, there is a good json library for c# that can be found here:
http://james.newtonking.com/json
Alternatively, since youre just doing an HTTP post and you only have one object, the fastest option would just be to write out the data line by line and have the recipient machine parse it. Since they both know what a LeadVM is, and both presumably have the same definition, it would be trivial to read a text string into the proper variables. This quickly becomes the slower option if you decide to add more object types to this process though.