I am using Xamarin.Forms and I am using HttpClient GetAsync and PostAsync to make calls to an api, my problem is the client is complaining that the application is too slow when it makes an api call. Is there anyways I can speed up this process or is there another faster way to call an api? Here is an example method:
public async Task<List<SubCatClass>> GetSubCategories(int category)
{
var client = new HttpClient();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("category", category.ToString())
});
var response = await client.PostAsync(string.Format("https://exmample.com/api/index.php?action=getSubCategories"), content);
var responseString = await response.Content.ReadAsStringAsync();
List<SubCatClass> items = JsonConvert.DeserializeObject<List<SubCatClass>>(responseString);
return items;
}
And here is how I am calling it.
await webService.GetSubCategories(item.categoryid);
The api I have full control over the code (PHP) and the server.
Any help would be much appreciated.
Thanks in advance.
UPDATE
I called the api in postman and here was the results
You can try using ModernHttpClient, it will increase your speed than using default by Xamarin
Related
I don't understand the variable types and how i can utilize client to retrieve the http Status code.
The client variable is a standard HttpClient object.
The attached picture is the function I'm trying to retrieve the status code during. Any help would be greatly appreciated.
[1]: https://i.stack.imgur.com/9iR3g.png
It should be easy as
var client = new HttpClient();
var results = await client.GetAsync("https://stackoverflow.com");
Console.WriteLine(results.StatusCode);
Your issue is that you're not getting response object. You are getting the content of the body of the response.
Here is a sample code:
void SimpleApiCall()
{
Uri endpoint = new Uri("https://www.7timer.info/bin/");
using var client = new HttpClient();
client.BaseAddress = endpoint;
// Get the response only here, and then get the content
// I'm using GetAwaiter().GetResult() because client.GetAsync() returns a Task and you're not using the async await since this is a button click event
var response = client.GetAsync("astro.php?lon=113.2&lat=23.1&ac=0&unit=metric&output=json&tzshift=0").GetAwaiter().GetResult();
// Status code will be available in the response
Console.WriteLine($"Status code: {response.StatusCode}");
// For the Reason phrase, it will be Ok for 200, Not Found for a 404 response...
Console.WriteLine($"Reason Phrase: {response.ReasonPhrase}");
// read the content of the response without the await keyword, use the .GetAwaiter().GetResult()
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Console.WriteLine("Content:");
Console.WriteLine(content);
}
Same goes for PostAsync and all the other operations...
I am facing an issue regarding not getting response from GetAsync API of HttpClient in MVC Applications(Target Framework - .Net Framework 4.7) whereas getting response in web services and console applications with same snippet. Here I have attached code snippet which I am trying to execute.
public void Get()
{
var response = Gettasks().Result;
}
public static async Task<HttpResponseMessage> GetTasks()
{
var response = new HttpResponseMessage();
try
{
using (var client = new HttpClient())
{
response = await client.GetAsync("https://www.google.com");
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
return response;
}
I am getting stuck on response = await client.GetAsync("https://www.google.com"); this line and not getting any response after executing this statement.
If anyone can please suggest solution for this or provide fix/solution which works for you.
You're seeing a deadlock because the code is blocking on an asynchronous method.
The best fix is to remove the blocking:
public async Task Get()
{
var response = await Gettasks();
}
This deadlock happens because await captures a context, and ASP.NET (pre-Core) has a context that only allows one thread at a time, and the code blocks a thread (.Result) in that context, which prevents GetTasks from completing.
Both the context and the blocking are necessary to see this kind of deadlock. In the other scenarios, there is no context, so that is why the deadlock does not occur. Since ASP.NET (pre-Core) has a context, the proper solution here is to remove the blocking.
Not sure whether you have tried following which is working for me.
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Environment.GetEnvironmentVariable("BaseAddress"));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestUri = Environment.GetEnvironmentVariable("Uri");
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
}
}
Seems like simple task, but the interwebs are flooded with different ways to approach this, so what is best practice for making a simple HTTP POST from asp.net Page_Load (I'm on .net 4.7) ?
Many resources point to the fact that HttpClient.PostAsync is the most lightweight approach.
However, the example here: https://learn.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45 - uses WebClient.
Also, both of theses approaches require setting Page Async="true" on the page - I am seeing conflicting information on whether this is actually the right approach.
Context: My page looks like it is spending a lot of time in BLOCKED_TIME during two requests that are made in Page_Load.
I suspect this is due to the way I currently make the POST:
public string makePost(string parametersToPassOn, string command)
{
HttpContent c = new StringContent(parametersToPassOn, Encoding.UTF8, "application/json");
var t = Task.Run(() => fireRESTcall(new Uri(walletProxyURL + command), c));
t.Wait();
return t.Result;
}
static async Task<String> fireRESTcall(Uri u, HttpContent c)
{
var response = string.Empty;
using (var client = new HttpClient())
{
HttpRequestMessage request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = u,
Content = c
};
HttpResponseMessage result = await client.SendAsync(request);
if (result.IsSuccessStatusCode)
{
response = await result.Content.ReadAsStringAsync();
}
}
return response;
}
Any help/thoughts would be greatly appreciated.
During the time your page makes an outgoing HTTP request, it can't do anything useful other than waiting for the response. See also Understanding BLOCKED_TIME in PerfView
You probably can't do anything about this delay, as you need the external API for some data, and you need to wait for it to complete in order to do something useful with that data.
So it's advisable to use async/await all the way, using RegisterAsyncTask():
void Page_Load()
{
RegisterAsyncTask(new PageAsyncTask(CallApiAsync));
Page.ExecuteRegisteredAsyncTasks();
}
async Task CallApiAsync() // calls
async Task<string> MakePost() // calls
async Task<String> FireRESTcall()
This frees up the thread to handle a new incoming request, until the outgoing request is finished and the incoming request continues on the same or another thread pool thread.
For this to work with WebForms, you do need Async="true" on your page.
I'm trying to call a webapi from a console application (which is triggered by windows task scheduler). I don't want my console app to wait for the result from api.I just want to call api and initiate it and exit the console application.
My console application code is
public static void InvokeSisService(string feature)
{
var serviceurl = ConfigurationManager.AppSettings["AppServiceURL"];
var controllerPath= ConfigurationManager.AppSettings["ControllerPath"];
var client = new HttpClient { BaseAddress = new Uri(serviceurl) };
controllerPath= controllerPath+ "?feature=" + feature;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
//client.PostAsync(smsservicepath, null);
// var temp=client.GetAsync(smsservicepath).Result;
var response = Task.Run(() => client.GetAsync(controllerPath)).Result;
}
My webapi is being called but it was waiting for the output.How do i exit console app after calling api.
Webapi code
[HttpGet]
[Route("ProcessService")]
public HttpResponseMessage ProcessService([FromUri] string feature)
{
}
I'm sure you want to make sure the response was received, so change
var response = Task.Run(() => client.GetAsync(controllerPath)).Result;
To:
using (var response = await client.GetAsync(controllerPath, HttpCompletionOption.ResponseHeadersRead))
This will drop after the response headers have been received. This does NOT include error handling - you should probably add error handling to the mix to make sure you are getting a proper response code before moving on - but that's up to you.
var response = Task.Run(() =>
client.GetAsync(controllerPath)).Result;
with the property "Result" you are waiting for the Response.
My .net application try to access external API by using the code below...
using (var keyClient = new HttpClient())
{
keyClient.BaseAddress = new Uri(ConfigurationManager.AppSettings["webshopurl"]);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("api_username",
ConfigurationManager.AppSettings["webshopAPIUserName"]),
new KeyValuePair<string, string>("api_password",
ConfigurationManager.AppSettings["webshopAPIPassword"])
});
var result = keyClient.PostAsync("/api/v1/key.php", content).Result;
token = result.Content.ReadAsStringAsync().Result;
}
When calling from local machine it works properly. But when it is hosted in online server URL such like http://app.test.net:5000/test it is not calling to the API. If we host such a URL like http://app.test.net/test it is working properly.
What is the reason for this?
Why are you using .Result to unpack the result? It's a lot better to use await to get the result from an async method.
.Result can cause a deadlock if you are not being careful with the context.
Stephen Cleary has a really nice articles that goes into more details.
Don't Block on Async Code