Issue with HttpClient.PostAsJsonAsync Not Working from ASPX - c#

I have created an ASP.NET Core 2.1 service and I can call it just fine from a console application. However, when I use the very same code to call it from an ASPX page, it does not return an answer. It just never goes past _client.PostAsJsonAsync and seems to run forever. It should only take a handful of seconds to go through that line. Any idea on what I am missing?
List<OutputAddress> outputAddresses = RunAsync(inputAddresses).GetAwaiter().GetResult();
static async Task<List<OutputAddress>> RunAsync(List<InputAddress> addresses)
{
// Update port # in the following line.
_client.BaseAddress = new Uri("http://<servername>/GeocodeAPI/");
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.Timeout = new TimeSpan(0, 10, 0);
try
{
HttpResponseMessage response = await _client.PostAsJsonAsync("api/Geocode/Addresses", addresses);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<List<OutputAddress>>(result);
}
else
return null;
}
catch (Exception e)
{
return null;
}
}
=======================
Huge thank you to Nkosi for their response. Here's what I had to change:
Function calling ASP.NET Core service
static async Task<List<OutputAddress>> RunAsync(List<InputAddress> addresses)
{
_client.BaseAddress = new Uri("http://<servername>/GeocodeAPI/");
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.Timeout = new TimeSpan(0, 10, 0);
try
{
HttpResponseMessage response = await _client.PostAsJsonAsync("api/Geocode/Addresses", addresses);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<List<OutputAddress>>(result);
}
else
return null;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
Function calling the above function (RunAsync): added async keyword
private async void ReadCsvFile(string filepath)
{
...
List<OutputAddress> outputAddresses = await RunAsync(inputAddresses);
...
}
Added Async="true" to aspx code:
<%# Page ... Async="true" %>

Mixing async-await and blocking calls like .Result; can cause deadlocks
await the calls to getting the content
var result = await response.Content.ReadAsStringAsync();
Also, if using async-await, go async all the way.
List<OutputAddress> outputAddresses = await RunAsync(inputAddresses);
Reference Async/Await - Best Practices in Asynchronous Programming

Beware of how you're using asynchronous code in ASP.NET Web Forms.
You need to use page async tasks.
That being said, nothing in async changes the HTTP protocol and, if you want some behavior on the client side, you need to implement it on the client, as Anu showed.

Related

App goes into Break Mode when I try to use Json with HttpClient

I am trying to post data from my app from a register page to a web service (testing with requestb.in) however when I try to use the below code it puts the app into break mode, then when I use break points to find where the problem is it just shows that "await PostRequest(...)" is causing the problem.
I have installed System.Net.Http on both the Portable project and the android project.
public async Task<JObject> PostAsync(string uri, string data)
{
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(uri, new StringContent(data));
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JObject.Parse(content));
}
Then for the button clicked where this method is called:
async void NextBtnClicked(object sender, EventArgs)
{
await PostAsync("https://requestb.in/MYURL", Username.Text);
}
Username.Text is the string from an entry field in the XAML class, This will recreate my problem
Here is the generic method I made to post data to an API.
As #maccettura pointed out above, it is best practice to reuse HttpClient and I've included that in the code, below.
HttpClient Post
static readonly Lazy<HttpClient> _clientHolder = new Lazy<HttpClient>(() => CreateHttpClient(TimeSpan.FromSeconds(60)));
static HttpClient Client => _clientHolder.Value;
protected static async Task<HttpResponseMessage> PostObjectToAPI<T>(string apiUrl, T data)
{
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(data)).ConfigureAwait(false);
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
try
{
return await Client.PostAsync(apiUrl, httpContent).ConfigureAwait(false);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
return null;
}
}
static HttpClient CreateHttpClient(TimeSpan timeout)
{
var client = new HttpClient();
client.Timeout = timeout;
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
return client;
}
This snippet was taken from my BaseHttpClientService.cs that I copy/paste into any app that needs to use HttpClient:
https://github.com/brminnick/XamList/blob/master/XamList/Services/BaseHttpClientService.cs
Troubleshoot your application using UWP so that you can see what kind of exception it is throwing. Try also to downgrade the two Nuget packages.

How to post data using HttpClient? (an answer than actually works)

There is another question about this, but it doesn't have a functioning solution at the end, and the only good answer, for some reason, doesn't work, not for the guy who ask it, not for me either.
This such question is here:
How to post data using HttpClient?
Given the corresponding aclarations, this is the code I have so far:
The methods to call the method who connects with the web server:
private void Button_Click(object sender, System.EventArgs e)
{
//. . . DO SOMETHING . . .
PopulateListView();
//. . . DO SOMETHING ELSE . . .
}
private void PopulateListView()
{
//. . . DO SOMETHING . . .
list = await "http://web.server.url".GetRequest<List<User>>();
//. . . DO SOMETHING ELSE . . .
}
The method than connects with the web server:
public async static Task<T> SendGetRequest<T>(this string url)
{
try
{
var uri = new Uri(url);
HttpClient client = new HttpClient();
//Preparing to have something to read
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("OperationType", "eaf7d94356e7fd39935547f6f15e1c4c234245e4")
});
HttpResponseMessage response = await client.PostAsync(uri, formContent);
#region - - Envio anterior (NO FUNCIONO, SIN USO) - -
//var stringContent = new StringContent("markString");
//var sending = await client.PostAsync(url, stringContent);
//MainActivity.ConsoleData = await client.PostAsync(url, stringContent);
#endregion
//Reading data
//var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
MainActivity.ConsoleData = json.ToString();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);
}
catch(Exception ex)
{
Console.WriteLine("Error: "+ex.ToString());
return default(T);
}
}
You maybe guessed it, but I'm trying to make a method that send some data (through POST) called "markString" to a web-server than receive it and, depending of the "markString" it returns certain json Objects.
This web server is already working properly (I tested it out with some plug-in, it work like it should)
This method is supposed to send the "markString" and receive the data back so then i can use it in the app.
I'm making a Xamarin Android application.
Also have in mind than I don't have any connection problem at all, in fact the app is sending data in an excellent matter when I try to do it using web client, but I want it to send it using HttpClient.
The problem
The code is not returning anything. Any request for information, clarification, question, constructive comments or anything than can lead to an answer would be greatly appreciated too.
Thanks in advance.
Most deadlock scenarios with asynchronous code are due to blocking further up the call stack.
By default await captures a "context" (in this case, a UI context), and resumes executing in that context. So, if you call an async method and the block on the task (e.g., GetAwaiter().GetResult(), Wait(), or Result), then the UI thread is blocked, which prevents the async method from resuming and completing.
void Main()
{
var test = SendGetRequest("http://www.google.com");
test.Dump();
}
public async static Task<string> SendGetRequest(string url)
{
try
{
var uri = new Uri(url);
HttpClient client = new HttpClient();
//Preparing to have something to read
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("OperationType", "eaf7d94356e7fd39935547f6f15e1c4c234245e4")
});
HttpResponseMessage response = await client.PostAsync(uri, formContent);
#region - - Envio anterior (NO FUNCIONO, SIN USO) - -
//var stringContent = new StringContent("markString");
//var sending = await client.PostAsync(url, stringContent);
//MainActivity.ConsoleData = await client.PostAsync(url, stringContent);
#endregion
//Reading data
//var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
return json;
}
catch (System.Exception ex)
{
Console.WriteLine("Error: " + ex.ToString());
return string.Empty;
}
}

Async function call issue

I am working on a Windows Phone application. While invoking the below function, after executing this line:
HttpResponseMessage response = await client.GetAsync(connection1).ConfigureAwait(false);
it skips the rest of the code and control goes to the parent function and execute the rest of the code there and come back to this function again. How to fix this problem?
public async void vehicleValidation()
{
//isValidVehicle = true;
var client = new System.Net.Http.HttpClient();
//string connection = "http://mymlcp.co.in/mlcpapp/get_slot.php?vehiclenumber=KL07BQ973";
string connection1 = string.Format("http://mymlcp.co.in/mlcpapp/?tag=GetIsValidUser&employeeId={0}&name={1}",txtVeh.Text,"abc");
HttpResponseMessage response = await client.GetAsync(connection1).ConfigureAwait(false);
//var response = await client.GetAsync(connection1);
// HttpResponseMessage response = client.GetAsync(connection1).Result;
var cont = await response.Content.ReadAsStringAsync();
var floorObj = Newtonsoft.Json.Linq.JObject.Parse(cont);
//var resp = await (new MLCPClient()).GetIsValidUser(txtVeh.Text, "xyz");
if (String.IsNullOrEmpty(floorObj["error"].ToString()) || floorObj["error"].ToString().Equals("true"))
{
isValidVehicle = false;
}
else
{
isValidVehicle = true;
}
}
You should never have async void unless you are writing a event handler, you need to make your function return a Task and then await the function in your parent function.
Read "Async/Await - Best Practices in Asynchronous Programming" for a introduction on the best practices like never doing async void and making your code "async all the way"

C# HttpClient to post information without waiting for response

I am using HttpClient class in my asp.net web api 2 application to post some information to a endpoint. I just want to post the information without waiting for a response. Is this the right syntax
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var gizmo = new Product() { Name = "Gizmo", Price = 100, Category = "Widget" };
var response = await client.PostAsJsonAsync("api/products", gizmo);
}
I just want to post the information without waiting for a response
Not awaiting an async method in WebAPI will result in a runtime exception, as the AspNetSynchronizationContext is aware of any triggered asynchronous operations. If it notices a controller action completes before the async operation has, it will trigger the said exception. More on that in ASP.NET Controller: An asynchronous module or handler completed while an asynchronous operation was still pending
If you want to use a fire and forget semantics, you need to queue the delegate via HostingEnvironment.QueueBackgroundWorkItem if you're using .NET 4.5.2 and above. If not, you can defer to using BackgroundTaskManager
Keep in mind this kind of design isn't really suitable for WebAPI. It doesn't scale if you're triggering this action call frequently. If this style happens often, consider using something more suitable such as a message broker.
To implement the async Task in ASP.NET refer to the following sample syntax:
protected void Page_Load(object sender, EventArgs e)
{
try
{
RegisterAsyncTask(new PageAsyncTask(LoadUrlContent));
}
catch {}
}
protected async Task LoadUrlContent()
{
try
{
// Add your code here, for example read the content using HttpClient:
string _content = await ReadTextAsync(YourUrl, 10);
}
catch { throw; }
}
Also, set <%# Page ... Async="true" %> at page level.
Following sample code snippet shows the use of HttpClient (call this sample function from LoadUrlContent():
protected async Task<string> ReadTextAsync(string Url, int TimeOutSec)
{
try
{
using (HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(TimeOutSec) })
{
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/html"));
using (HttpResponseMessage _responseMsg = await _client.GetAsync(Url))
{
using (HttpContent content = _responseMsg.Content)
{
return await content.ReadAsStringAsync();
}
}
}
}
catch { throw; }
}
You can modify this code base pertinent to your particular task.
Hope this may help.

Making Http Call from c#

There is a classic asp application which makes calls to .shtml files using AspHttp.Conn. It makes the request by appending all the input and also reads the response by reading the values in the response by length.
Here is the example
strMessage= "test.shtml"
Set HttpObj = Server.CreateObject("AspHTTP.Conn")
HttpObj.Url = url & strMessage
HttpObj.PostData = "testarea=" & strRequestData
HttpObj.TimeOut = 60
HttpObj.RequestMethod = "post"
strResponseData = HttpObj.GetURL
Response.Write Mid(strResponseData,3,1)
Response.Write Mid(strResponseData,4,3)
If I need to rewrite this, what will be the best way to do this. I will be using MVC and will be rewriting the UI. what will be the best approach to make httpcall from c#?. The backend to which the request will be sent will not be changed. Please suggest.
Using .Net Framework 4.5 you can make request as
public static async Task<int> HtmlLoadAsync(string url/*, bool addUserAgent = false*/)
{
try
{
var client = new HttpClient();
//if (addUserAgent) OPTIONAL
//{
// client.DefaultRequestHeaders.UserAgent.ParseAdd(UserAgent);
//}
//client.Timeout = TimeOut;
var response = client.GetStringAsync(url); //here you can change client method according to your required outpu
var urlContents = await response;
// process urlContents now
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return 0;
}
Now call it as
private async void Process()
{
await HtmlLoadAsync("http://....");
}
Note: You must have to add reference System.Net.Http

Categories