I'm trying to get response a external API using httpclint in .netcore5.0.
Initially I got timeout exception. So I add client.Timeout = Timeout.InfiniteTimeSpan; after adding this response is come. but it takes more than 20 mins.
But I browser I can get API result within milliseconds.
How can I get response from API with a short time. Any idea to decrease this responding time?
startup.cs
services.AddHttpClient<IHolidayService, HolidayService>("PublicHolidaysApi", c => c.BaseAddress = new Uri("https://api.xmltime.com"));
service.cs
public class HolidayService : IHolidayService
{
private readonly IHttpClientFactory _clientFactory;
private readonly HttpClient _client;
public HolidayService(HttpClient client)
{
_client = client;
client.Timeout = Timeout.InfiniteTimeSpan;
}
public HolidayService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
_client = clientFactory.CreateClient("PublicHolidaysApi");
}
public async Task<Holiday> GetHolidays(string country,int year)
{
string url = string.Format($"/holidays?accesskey="MyAccessKey"&secretkey="MySecretKey"&version=3&country=ro&year=2021&lang=en");
var result = new Holiday();
using (var cts = new CancellationTokenSource(Timeout.InfiniteTimeSpan))
{
var response = await _client.GetAsync(url, cts.Token).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
result = await JsonSerializer.DeserializeAsync<List<Holiday>>(responseStream);
}
else
{
throw new HttpRequestException(response.ReasonPhrase);
}
}
return result;
}
}
}
model
public class Holiday
{
[JsonPropertyName("urlid")]
public string UrliId { get; set; }
[JsonPropertyName("url")]
public string Url { get; set; }
[JsonPropertyName("country")]
public Country Country { get; set; }
[JsonPropertyName("name")]
public Name Name { get; set; }
[JsonPropertyName("oneliner")]
public OneLiner OneLiner { get; set; }
[JsonPropertyName("date")]
public Date Date { get; set; }
[JsonPropertyName("types")]
public List<string> Types { get; set; }
[JsonPropertyName("uid")]
public string UId { get; set; }
}
public class Country
{
[JsonPropertyName("id")]
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
public class Name
{
[JsonPropertyName("lang")]
public string Lang { get; set; }
[JsonPropertyName("text")]
public string Text { get; set; }
}
public class OneLiner
{
[JsonPropertyName("lang")]
public string Lang { get; set; }
[JsonPropertyName("text")]
public string Text { get; set; }
}
public class Date
{
[JsonPropertyName("iso")]
public string iso { get; set; }
[JsonPropertyName("datetime")]
public DateTime? Datetime { get; set; }
}
}
There are so many possibilities in this situation and I can only give you a way to solve the problem.
First of all, we need to locate the reason why it is so slow. Is it the server or the client?
We can use packet capture tools such as Fiddler ,and then observe the corresponding network requests.
If client had send but server not response , you should think about the api limit...
And if not, the request are not send at all, may be you should the check the connection pool of the HttpClient, or the WorkThreadPool of dotnet.
there are a few problems with your question.
it doesn't compile.
it is incomplete.
it has sensitive data.
but I can get the data from API in no time. just open this link https://dotnetfiddle.net/ryjakT and run the program.
I changed few things
Return Type, it should be List
var result = new Holiday(); to var result = new List();
I am using Newtonsoft.Json for Deserialization.
you were trying to Deserialize to an incorrect model, it should be Root.
Related
I am testing request for API from Baselinker. I have created simple app in c#, which takes input as JSON file with parameters, then converts it to API request model, send it to API and receive response.
But I have problem with one request, https://api.baselinker.com/index.php?method=getOrders. When I try to get orders from my test account by this request I got response "Order source does not exist.", idk why - I have checked every variable in my class which represents this request but didn't find anything wrong. When I do the same on testing API request site (https://api.baselinker.com/index.php?tester) it works correct.
Here is my source code:
Class representing getOrder request:
public class GetOrders : IRequest<GetOrders.Response> {
[JsonPropertyName("order_id")]
public int? OrderId { get; set; }
[JsonPropertyName("date_confirmed_from")]
public int? DateConfirmedFrom { get; set; }
[JsonPropertyName("date_from")]
public int? DateFrom { get; set; }
[JsonPropertyName("id_from")]
public int? IdFrom { get; set; }
[JsonPropertyName("get_unconfirmed_orders")]
public bool? GetUnconfirmedOrders { get; set; }
[JsonPropertyName("include_custom_extra_fields")]
public bool? IncludeCustomExtraFields { get; set; }
[JsonPropertyName("status_id")]
public int? StatusId { get; set; }
[JsonPropertyName("filter_email")]
public string? FilterEmail { get; set; }
[JsonPropertyName("filter_order_source")]
public string? FilterOrderSource { get; set; }
[JsonPropertyName("filter_order_source_id")]
public int? FilterOrderSourceId { get; set; }
public class Product {
```Product class properties...```
}
public class Order {
```Order class properties...```
}
public class Response : Output {
[JsonPropertyName("orders")]
public List<Order> Orders { get; set; }
}
}
Class sending requests:
public class BaselinkerRequestManager {
private string _token;
private const string _url = "https://api.baselinker.com/connector.php";
public BaselinkerRequestManager(string token) { _token = token; }
private string GetRequestMethodName(object userRequest) {
return JsonNamingPolicy.CamelCase.ConvertName(userRequest.GetType().Name);
}
private RestRequest CreateRequest(string method, object parameters) {
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("X-BLToken", _token);
request.AddParameter("method", method);
if ( parameters != null ) {
request.AddParameter("parameters", JsonSerializer.Serialize(parameters));
}
return request;
}
private async Task<RestResponse> ExecuteRequestAsync(RestClient client, RestRequest request) {
return await client.ExecuteAsync(request);
}
//TResponse - generic which represents Response Class in each Request
public async Task<TResponse> SendRequestAsync<TResponse>(IRequest<TResponse> userRequest) {
var client = new RestClient(_url);
var method = GetRequestMethodName(userRequest);
var request = CreateRequest(method, userRequest);
var response = await ExecuteRequestAsync(client, request);
return JsonSerializer.Deserialize<TResponse>(response.Content);
}
}
Here is call:
var requestManager = new BaselinkerRequestManager("token_to_connect");
//this request doesn't need parameters so i dont have to initialize it
var r_getOrders = await requestManager.SendRequestAsync(new Requests.Orders.GetOrders());
Via an http Post, I send html FormData to my Web Api2 controller.
The FormData contains one or more images, as well as client properties.
My front end Angular 5 service sends the http post (working fine):
var url = this.host + 'import/MediaUpload';
return this.http.post(url, formData, options)
.map((result: any) => result._body)
.catch(this.handleError);
I would like to convert the FormData to a generic List of MediaInfo class (defined below this MediaUpload() method) :
public async Task<HttpResponseMessage> MediaUpload(int projectId, int sectionId)
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = await Request.Content.ReadAsMultipartAsync<InMemoryMultipartFormDataStreamProvider>(new InMemoryMultipartFormDataStreamProvider());
//access form data
NameValueCollection formData = provider.FormData;
List<MediaInfo> listMedia = new List<MediaInfo>();
//dynamic jsonData = JObject.Parse(formData["MediaInfo"]); // THROWS ERROR
JArray ary = JArray.Parse(formData["MediaInfo"]);
foreach (var item in ary) {
//listMedia.Add((MediaInfo)item); // ???
Console.WriteLine(item);
}
//access files
IList<HttpContent> files = provider.Files;
HttpContent file1 = files[0];
var thisFileName = file1.Headers.ContentDisposition.FileName.Trim('\"');
// additional file upload code removed, working fine..
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("DocsUrl", URL);
return response;
}
public class MediaInfo
{
public string PatientID { get; set; }
public string PatientFirstName { get; set; }
public string PatientLastName { get; set; }
public string PatientUID { get; set; }
public string PatientDOB { get; set; }
public string ExamDate { get; set; }
public string ExamDevice { get; set; }
public string SerialNo { get; set; }
public string Eye { get; set; }
public int DeviceID { get; set; }
public int CSIInstanceID { get; set; }
public int MediaNo { get; set; }
public string Procedure { get; set; }
public string FileName { get; set; }
public int FileSize { get; set; }
}
I thought I could do something like :
listMedia.Add((MediaInfo)item;
But I'm missing the correct conversion somewhere.
You can convert a JObject to a type of your choosing with the .ToObject<T>() method.
https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JToken_ToObject__1_1.htm
In this case you want your code to look like this:
listMedia.Add(item.ToObject<MediaInfo>());
You could also use JsonConvert.DeserializeObject to convert it directly into the desired type provided formData["MediaInfo"] returned well formed JSON.
List<MediaInfo> listMedia = JsonConvert.DeserializeObject<List<MediaInfo>>(formData["MediaInfo"]);
I am doing server to server communication and I am getting data back from my api. I using Http web client to do that. This is my code
public async Task<List<Report>> GetReports(string tokenType, string token, int page, int count)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, token);
var builder = new UriBuilder(ApiEndPointBase + "api/" + ApiVersion + "/LibraryDocument");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["page"] = page.ToString();
query["count"] = count.ToString();
builder.Query = query.ToString();
string url = builder.ToString();
var result = await client.GetAsync(url);
if (!result.IsSuccessStatusCode)
throw new Exception("");
List<Report> reports = new List<Report>();
await result.Content.ReadAsAsync<List<Report>>().ContinueWith(response =>
{
reports = response.Result;
});
return reports;
}
The issue I am having is that I am getting data from server in this format
public class Report
{
public int pK_LibraryDocument { get; set; }
public string fileName { get; set; }
public List<string> AvailableForModules { get; set; }
}
But I want data like this
public class Report
{
public int id{ get; set; }
public string fileName { get; set; }
public List<string> AvailableForModules { get; set; }
}
I would probably have other variable name changes as well. The reason for that is that I would have multiple data sources with same data but the format or name would be different. So I want to have a centralize naming for my self.
Is it possible in a not expensive (time consuming) way.
JSON.NET that is used by default for deserialization supports JsonProperty attribute for adjusting JSON field name:
public class Report
{
[JsonProperty("pK_LibraryDocument")]
public int id { get; set; }
public string fileName { get; set; }
public List<string> AvailableForModules { get; set; }
}
I am able to handle simple JSON serialization and deserialization but this API response seems little complicated, and I am seeking an advice as to what would be ideal approach to tackle this.
I'm trying to call an API for MVC application.
Goal is to map API data to model.
API endpoint is
https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=1min&apikey=MyAPIKey
Troubles here are:
JSON data keys have white space in them.
When I tried doing paste special in Visual studio, It gave me a long
list of classes for each date entry separately, because this API
call returns a separate set of information for date.
To solve problem explained in point 1, I used [JsonProperty("1. Information")] in class. And in my code..
public async Task TSI()
{
HttpClient client = new HttpClient();
//Uri uri = new Uri("http://date.jsontest.com/");
Uri uri = new Uri("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=5min&apikey=demo");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
dynamic result = await response.Content.ReadAsAsync<object>();
IEnumerable<dynamic> dObj = JsonConvert.DeserializeObject<dynamic>(result.ToString());
IEnumerable<dynamic> t1 = dObj.FirstOrDefault();
IEnumerable<dynamic> t2 = dObj.LastOrDefault();
dynamic MetaData = t1.FirstOrDefault();
Rootobject ro = new Rootobject();
ro.MetaData = MetaData;
}
PS: I'm relatively new to make API calls and handling them.
I was able to make a call to
date.jsontest.com
and map the API data to model (which I had created using paste special)
//API response
{
"time": "12:53:22 PM",
"milliseconds_since_epoch": 1504875202754,
"date": "09-08-2017"
}
//C# code to map to API data
public class sampleObject
{
public string time { get; set; }
public long milliseconds_since_epoch { get; set; }
public string date { get; set; }
}
My RootObject looks like this:
public class Rootobject
{
[JsonProperty("Meta Data")]
public MetaData MetaData { get; set; }
[JsonProperty("Time Series (1min)")]
public TimeSeries1Min TimeSeries1min { get; set; }
}
public class MetaData
{
[JsonProperty("1. Information")]
public string _1Information { get; set; }
[JsonProperty("2. Symbol")]
public string _2Symbol { get; set; }
[JsonProperty("3. Last Refreshed")]
public string _3LastRefreshed { get; set; }
[JsonProperty("4. Interval")]
public string _4Interval { get; set; }
[JsonProperty("5. Output Size")]
public string _5OutputSize { get; set; }
[JsonProperty("6. Time Zone")]
public string _6TimeZone { get; set; }
}
// I have so many of these sub-classes for dates, which again is an issue
public class TimeSeries1Min
{
public _20170907160000 _20170907160000 { get; set; }
public _20170907155900 _20170907155900 { get; set; }
....
....}
public class _20170907160000
{
public string _1open { get; set; }
public string _2high { get; set; }
public string _3low { get; set; }
public string _4close { get; set; }
public string _5volume { get; set; }
}
public class _20170907155900
{
public string _1open { get; set; }
public string _2high { get; set; }
public string _3low { get; set; }
public string _4close { get; set; }
public string _5volume { get; set; }
}
It is hard to create a model from this json, but you can convert those data to dictionary
var jObj = JObject.Parse(json);
var metadata = jObj["Meta Data"].ToObject<Dictionary<string, string>>();
var timeseries = jObj["Time Series (1min)"].ToObject<Dictionary<string, Dictionary<string, string>>>();
The following code should do what you want
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<Rootobject>(result);
//No idea what you want to do with this line as there is no MetaData property on the root object
obj.MetaData = MetaData;
}
I am new to asp.net mvc webapi.I am create one webapi service.In this service I am sending parameter as an array class.
Below is my service :
[AcceptVerbs("GET", "POST")]
public HttpResponseMessage addBusOrder(string UserUniqueID, int PlatFormID,
string DeviceID, int RouteScheduleId,
string JourneyDate, int FromCityid,
int ToCityid, int TyPickUpID,
Contactinfo Contactinfo, passenger[] pass)
{
//done some work here
}
public class Contactinfo
{
public string Name { get; set; }
public string Email { get; set; }
public string Phoneno { get; set; }
public string mobile { get; set; }
}
public class passenger
{
public string passengerName { get; set; }
public string Age { get; set; }
public string Fare { get; set; }
public string Gender { get; set; }
public string Seatno { get; set; }
//public string Seattype { get; set; }
// public bool Isacseat { get; set; }
}
Now how to pass passenger and contactinfo parameters to the above service.
Is there any changes in webapiconfig file?
i want to pass passenger details like this:
passengername="pavan",
age="23",
Gender="M",
passengername="kumar",
Gender="M",
Age="22
It will be much neater if you can create model of your parameter. To pass them from client side, you need to format them using one of data-interchange format. I prefer use JSON provided by Newtonsoft.Json library. Sending process is handled by HttpClient class provided by System.Net.Http namespace. Here is some sample:
Server Side
//Only request with Post Verb that can contain body
[AcceptVerbs("POST")]
public HttpResponseMessage addBusOrder([FromBody]BusOrderModel)
{
//done some work here
}
//You may want to separate model into a class library so that server and client app can share the same model
public class BusOrderModel
{
public string UserUniqueID { get; set; }
public int PlatFormID { get; set; }
public string DeviceID { get; set; }
public int RouteScheduleId { get; set; }
public string JourneyDate { get; set; }
public int FromCityid { get; set; }
public int ToCityid { get; set; }
public int TyPickUpID { get; set; }
public Contactinfo ContactInfo { get; set; }
public passenger[] pass { get; set; }
}
Client Side
var busOrderModel = new BusOrderModel();
var content = new StringContent(JsonConvert.SerializeObject(busOrderModel), Encoding.UTF8, "application/json");
using (var handler = new HttpClientHandler())
{
using (HttpClient client = new HttpClient(handler, true))
{
client.BaseAddress = new Uri("yourdomain");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return await client.PostAsync(new Uri("yourdomain/controller/addBusOrder"), content);
}
}
Here's how you can do it:
First, since you are passing two objects as parameters we'll need a new class to hold them (because we can only bind one parameter to the request's content):
public class PassengersContact
{
public Passenger[] Passengers { get; set; }
public Contactinfo Contactinfo { get; set; }
}
and now for your controller (this is just a test controller):
[RoutePrefix("api")]
public class DefaultController : ApiController
{
[HttpPost]
// I prefer using attribute routing
[Route("addBusOrder")]
// FromUri means that the parameter comes from the uri of the request
// FromBody means that the parameter comes from body of the request
public IHttpActionResult addBusOrder([FromUri]string userUniqueId,
[FromUri]int platFormId,
[FromUri]string deviceId, [FromUri]int routeScheduleId,
[FromUri]string journeyDate, [FromUri]int fromCityid,
[FromUri]int toCityid, [FromUri]int tyPickUpId,
[FromBody]PassengersContact passengersContact)
{
// Just for testing: I'm returning what was passed as a parameter
return Ok(new
{
UserUniqueID = userUniqueId,
PlatFormID = platFormId,
RouteScheduleId = routeScheduleId,
JourneyDate = journeyDate,
FromCityid = fromCityid,
ToCityid = toCityid,
TyPickUpID = tyPickUpId,
PassengersContact = passengersContact
});
}
}
Your request should look something like this:
POST http://<your server's URL>/api/addBusOrder?userUniqueId=a&platFormId=10&deviceId=b&routeScheduleId=11&journeyDate=c&fromCityid=12&toCityid=13&tyPickUpId=14
Content-Type: application/json
Content-Length: 110
{
"passengers" : [{
"passengerName" : "name",
"age" : 52
/* other fields go here */
}
],
"contactinfo" : {
"name" : "contact info name",
/* other fields go here */
}
}
Notice the api/addBusOrder comes from concatenating the values of the RoutePrefix/Route attributes.