I am working on Market and Financial News app.I took the API from https://www.marketaux.com/. I am trying to display the news from the site into my home page. I have created a model file and controller in ASP.NET Core web app file. In controller file, I get an error in response.data part as its showing response doesn't have data object whereas when I print the output of response.Content, it has data object. Can you tell me how to solve this and get access to the data from the API so that I can display it on my Home page?
Controller class:
using System.Runtime.CompilerServices;
using Azure.Core;
using MarketNews.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MySql.Data.MySqlClient;
using MySqlX.XDevAPI;
using Newtonsoft.Json;
using RestSharp;
namespace MarketNews.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class NewsController : ControllerBase
{
[HttpGet]
public News[] GetNews()
{
List<News> news = new List<News>();
RestClient client = new RestClient("https://api.marketaux.com/v1/news/all");
// client.Timeout = -1;
RestRequest request = new RestRequest("News",Method.Get);
request.AddQueryParameter("api_token", "qIWtsblpK93oeo23o87egUGBoVmVaqkl4fdHRTEc");
request.AddQueryParameter("symbols", "aapl,amzn");
request.AddQueryParameter("limit", "50");
RestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
if (response != null)
{
foreach (var article in response.data)
{
news.Add(new News
{
Title = article.title,
Description = article.description,
Url = article.url,
Url_Image = article.image_url,
Published_At = article.published_at
});
}
}
return news.ToArray();
}
}
}
Model class
namespace MarketNews.Models
{
public class News
{
public string Title;
public string Description;
public string Url;
public string Url_Image;
public DateTime Published_At;
}
}
I wanted to get data from the API and display it on my Home Page. I used RestClient and RestRequest to get response and then from response. I got the output when response.Content printed to console, it is working and it gave me a json file as output. In foreach loop when I tried to set the response data to the model data I created, it's showing response.data doesn't exist.
I want to know what is wrong here or is there any other method to get the data from the API?
Api: Website link
From RestSharp documentation, the Execute() method does support for a generic type.
Execute<T>(IRestRequest request)
Note that, this method is deprecated. You shall look for the method below:
ExecuteAsync<T>(IRestRequest request, CancellationToken cancellationToken)
and revamp your API action to support asynchronous operation.
From the response data shared in the link, you need a Root object which contains the data property with the List<New> type.
Define the data model class for the response.
using System.Text.Json;
public class Root
{
[JsonPropertyName("data")]
public List<News> Data { get; set; }
}
public class News
{
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("url")]
public string Url { get; set; }
[JsonPropertyName("image_url")]
public string Url_Image { get; set; }
[JsonPropertyName("published_at")]
public DateTime Published_At { get; set; }
}
For the caller, specify the generic type as Root. Next extract the data property from the response with response.Data.Data.
RestResponse<Root> response = client.Execute<Root>(request);
// asynchronous way
// RestResponse<Root> response = await client.ExecuteAsync<Root>(request);
if (response != null)
news = response.Data.Data;
Related
In My code, I am trying to receive an API containing a JSON body containing data, I have designed a DataInfo Model class and used the [FromBody] function to translate the data.
My issue is that the data being pulled which I have formatted to be ints and doubles, is being pulled as a series of 0s
My Data Info Model Class:
public class DataInfo
{
[JsonProperty("ID")]
public int JId { get; set; }
[JsonProperty("Temp")]
public double JTemperature { get; set; }
[JsonProperty("Humidity")]
public double JHumidity { get; set; }
[JsonProperty("WindSpeed")]
public double JWindSpd { get; set; }
[JsonProperty("SoilMoisture")]
public double JSM { get; set; }
}
}
My Api Controller:
[HttpPatch("update")]
public async Task<ActionResult<Device>> Update([FromBody] DataInfo data)
{
var dev = await _dbContext.Device.Where(x => x.Id == data.JId).FirstOrDefaultAsync();
if (dev == null)
{
return BadRequest("no device found");
}
dev.Humidity = data.JHumidity;
dev.Temp = data.JTemperature;
dev.WindSpeed = data.JWindSpd;
dev.SoilMoisture = data.JSM;
dev.DateTime = DateTime.Now;
_dbContext.SaveChanges();
return Ok(dev);
}
My JsonBody:
{
"ID":"1",
"Temp":"37",
"Humidity":"42",
"WindSpeed":"12",
"SoilMoisture":"14"
}
I also Used this JSON body and got the same result:
{
"data":{
"ID":"1",
"Temp":"37",
"Humidity":"42",
"WindSpeed":"12",
"SoilMoisture":"14"
}
}
When I run the API call in postman, I receive a 400 error with the text that correlates to an invalid Device ID, when I had it send the Device ID and other data points within the class, all were returned as 0s.
The API call is going to the correct controller, however the JSON data seems only to be exsisting as 0s even though I assign it with the JsonPropertyName or JsonProperty assignment in the model class.
I found the issue to be in My Using inputs. I was including Newtonsoft which was conflicting with system.
using BlazorApp1.Data;
using BlazorApp1.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
//using Newtonsoft.Json;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
I'm trying to do a patch with web api. I keep getting NULL for my json. Please Help
Here is my Json
[{"PartNumber":"AN33016UA-VB"}{"Category":"Chassis"}]
Here is my my class
public class wsCategory
{
public string PartNumber { get; set; }
public string Category { get; set; }
}
Here is my Api Controller
[HttpPatch]
[ActionName("IMDSCategory")]
public HttpResponseMessage IMDSCategory([FromBody]wsCategory jsonbody)
{
var data = jsonbody.PartNumber;
return new HttpResponseMessage(HttpStatusCode.Created);
}
The JSON is inavalid.
[{"PartNumber":"blahblah","Category":"Chassis"}]
I believe the array container will be parsed out correctly, but I'm on a chromebook right now, so I can't check that. If it still fails, drop the [].
based on your method
[HttpPatch]
[ActionName("IMDSCategory")]
public HttpResponseMessage IMDSCategory([FromBody]wsCategory jsonbody){...}
Your JSON is invalid given the model you are trying to parse.
[{"PartNumber":"AN33016UA-VB"}{"Category":"Chassis"}]
should be
{"PartNumber":"AN33016UA-VB","Category":"Chassis"}
How should I post a collection of objects to a WEB API Rest service?
This is what I have in my Rest service..
I am using XmlSerializer
Here is the ActionMethod
public class DevicesController : ApiController
{
[HttpPost]
public void PushToDb([FromBody] device[] devices)
{
var iCount = devices.Count();
...
...
}
Here is the device DTO:
public class device
{
public string serialnumber { get; set; }
public string hw_part_id { get; set; }
}
Here is the Request:
http://localhost:50384/api/Devices/PushToDb
And the XML input
<devices>
<device
<serialnumber>1</serialnumber>
<hw_part_id>A</hw_part_id>
</device>
<device>
<serialnumber>2</serialnumber>
<hw_part_id>A</hw_part_id>
</device>
</devices>
Content-Type is set as application/xml.
When I send this Post request, devices is always null. But if I change the Action method to just accept one device, I am able to receive the device data in the Action method.
Only when I am passing a collection I am not able to receive the input in the Action method.
Am I missing something? What should I do to be able to post a collection (XML input) to ASP.NET Rest service?
Thanks in advance.
Rag
As said in the comment decorate your class this way
[DataContract]
public class device
{
[DataMember]
public string serialnumber { get; set; }
[DataMember]
public string hw_part_id { get; set; }
}
Then use newtonsoft (or any other library) to serialize an array of device type to json. and use System.Net.WebClient this way:
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
var jsonObj = JsonConvert.SerializeObject(yourArray); //yourArray is a device[]
client.UploadString(ApiServiceUrl, jsonObj);
}
dear take a small break from work and watch this MVA Course, it will definitely solve your problem
https://www.microsoftvirtualacademy.com/en-us/training-courses/web-api-design-jump-start-8689?l=BMxSvaH1_3804984382
thank you
I have Web API service deployed and and consuming in another web application. Web API method take complex object (List object) and results also complex object.
So I created local models for Input parameter and results model to match with Web API complex objects in web application. then I passed JsonConvert.SerializeObject for that parameter. But when I debug in Web API that parameter value showing null.
Web application
[Serializable]
public class PreferencesInput
{
public string ShortName { get; set; }
public string ShortNameDescription { get; set; }
.....
}
[Serializable]
public class PreferencesOuput
{
public bool Status { get; set; }
public string Error { get; set; }
}
public class HomeController : Controller
{
public ActionResult Index()
{
RunAsync().Wait();
return View();
}
private static async Task RunAsync()
{
var inputs = new List<PreferencesInput>();
var input = new PreferencesInput
{
ShortName = "REGION",
ShortNameDescription = "Geographical regions",
OptedInFlag = true
};
inputs.Add(input);
....
...
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8585/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = await client.GetAsync("preferences/updatepreferences/?id='3016523'
&optInInterestAreas=" + JsonConvert.SerializeObject(inputs) +
"&solicitationFlag=false").ConfigureAwait(false);;
if (response.IsSuccessStatusCode)
{
string results = await response.Content.ReadAsStringAsync();
var myList = JsonConvert.DeserializeObject<List<PreferencesOuput>>(results);
}
web API
[Route("preferences/updatepreferences")]
[HttpGet]
public PreferencesOuput UpdatePreferences(string id, IEnumerable<PreferencesInput> optInInterestAreas, bool solicitationFlag)
{
.....
}
Only difference is Web application Input model has less parameters than the Web API model.
What I am doing wrong here?
IEnumerable<PreferencesInput> optInInterestAreas is null
update
I can see serialization date like below before sending to Web API call, In Web API method it is showing null, rest of the parameters are showing correct.
[{"ShortName":"REGION","ShortNameDescription":"Geographical regions","ShortSubName":null,"Description":null,"OptedInFlag":true},
{"ShortName":"REGION","ShortNameDescription":"Asia Pacific","ShortSubName":"ASIA_PACIFIC","Description":null,"OptedInFlag":true},
{"ShortName":"REGION","ShortNameDescription":"Canada","ShortSubName":"CANADA","Description":null,"OptedInFlag":true}]
You could try to specify the route with parameters. Something like:
[Route("preferences/updatepreferences/{id}/{optInInterestAreas}/{solicitationFlag:bool}")]
Your optInInterestAreas parameter is null because in Web API, the parameter binding rules specify that anything other than a "simple" parameter type (string, int, etc) is assumed to be passed in the body, not the route or query string as you're doing. You could get this to work by using the [FromUri] attribute on that parameter or by defining a custom type converter, but I would highly recommend changing your API as it does not follow generally accepted best practices.
By convention, GET is assumed to be side-effect-free, but I'm guessing something called UpdatePreferences almost certainly changes data. I would consider using a different verb and passing the updated preferences in the body. POST is better, but if you want it to be truly RESTful, you should ensure that the URI uniquely identifies the resource and use PUT.
I would start by changing your input model to something like this:
public class PreferencesInput
{
public IList<InterestArea> InterestAreas { get; set; }
public bool SolicitationFlag { get; set; }
}
public class InterestArea
{
public string ShortName { get; set; }
public string ShortNameDescription { get; set; }
...
}
Then define your API action like this:
[Route("preferences/{id}")]
[HttpPut]
public PreferencesOuput UpdatePreferences(string id, PreferencesInput preferences)
{
...
}
As you can see, the URI now uniquely identifies the thing, and the verb specifies what you want to "do"; in this case, completely replace whatever is at that URI (if anything) with the thing you are passing.
Side-note:
On the MVC side, calling Wait() in your Index action is blocking a thread while waiting for your async method to complete. That's a serious invitation for deadlocks. Async only works properly if you go "all the way" with it. In this case it's incredibly easy - just change the Index action to:
public async Task<ActionResult> Index()
{
await RunAsync();
return View();
}
I'm developing a web service, using WEB .API. I'm following the example, which include:
public HttpResponseMessage PostProduct(Product item)
{
item = repository.Add(item);
var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
for creating a POST method, allowing a client to send data in POST in ordert to insert these data in the database (I'm using Entity Framework).
What I want do, however, is slightly difference, since the data I want pass in post to the web service are not associated to any object of database: I have some data that should be write in more then one table. For example:
{"activity":"sport","customValue":"22","propertyIndex":"122-x"}
The activty value (sport) should be writed on one table, while the others two parameters (customValue e properyIndex) shouldbe writed on another table.
So I think I need to parse the json file received in POST and then execute the two insert operation.
How can I perform this task?
You need to create an object in web API project with Activity, CustomValue, PropertyIndex properties:
public class MyTestClass
{
public string Activity { get; set; }
public string CustomValue { get; set; }
public string PropertyIndex { get; set; }
}
and HttpPost will be:
[HttpPost]
public HttpResponseMessage Post(MyTestClass class)
{
// Save Code will be here
return new HttpResponseMessage(HttpStatusCode.OK);
}
Product class should have Activity, CustomValue and PropertyIndex properties to get bind with posted data.
[HttpPost]
[ActionName("alias_for_action")]
public HttpResponseMessage PostProduct([FromBody] Product item)
{
//your code here
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent("Your Result")
};
return response;
}
Yes if you want to update two tables in database using Entity Framework then you have to execute two insert operations.