Making Http Call from c# - 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

Related

UI thread waits for "await client.SendAsync(request).ConfigureAwait(false)" to finish before moving to another url

Client starts some action via button. In controller its async method: async public Task<JsonResult> CreatePresentation that contains line using (var response = await client.SendAsync(request).ConfigureAwait(false)). Lets say this line takes 10s to finish. While that is happenning client wants to go to another url inside website and clicks on that url (that view is also async meaning its async public Task<ActionResult> BRDetails(int id)). But asp .net does not serve him view immidiatly. Instead it awaits for await line to finish before serving him the view (10s).
Why does asp framework waits for await line to finish before it starts producing view for next url that client requested?
I would thought that deliving the next url should start immidiatly in second thread and waits in first for await to finishes because of .ConfigureAwait(false).
Environment:
.net framework v4.5,
iiexpress that comes with visual studio
Here is part of code (since it's a software product I am not able to share full code):
async public Task<JsonResult> CreateReportFile(int id, string email)
{
try
{
var fileName = "Report " + DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss") + ".txt";
fileName = fileName.Replace('/', '_');
fileName = fileName.Replace(':', '_');
var fullPath = "some path";
var presentationTask = new Creator().CreateSomeFile("some values to pass", fileName);
var ms = await presentationTask.ConfigureAwait(false);
using (FileStream file = new FileStream(fullPath, FileMode.Create, System.IO.FileAccess.Write))
{
ms.WriteTo(file);
ms.Close();
}
var emailAttachment = BusinessReportsEmail.savePresentation(fullPath, fileName);
await BusinessReportsEmail.sendEmail(emailAttachment, email).ConfigureAwait(false);
return Json(new
{
Status = "ok",
Data = email
});
}
catch (Exception ex)
{
return Json(new
{
Status = "error",
Data = ex.Message
});
}
}
public async Task<MemoryStream> CreateSomeFile(string programData, string outputFileName)
{
// Use this in production
var url = string.Format(System.Configuration.ConfigurationManager.AppSettings["workFileUrl"]);
var appCode = string.Format(System.Configuration.ConfigurationManager.AppSettings["appCode"]);
var appKey = string.Format(System.Configuration.ConfigurationManager.AppSettings["appKey"]);
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(20);
using (var request = new HttpRequestMessage(HttpMethod.Post, url))
{
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Add("AppCode", appCode);
request.Headers.Add("AppKey", appKey);
var jsonString = JsonConvert.SerializeObject(new
{
InputType = "json",
Content = programData
});
request.Content = new StringContent(jsonString, Encoding.UTF8, "application/json");
using (var response = await client.SendAsync(request).ConfigureAwait(false))
{
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception($"Failed to create {outputFileName} file.");
var reponseObject = await response.Content.ReadAsAsync<FileResponse>().ConfigureAwait(false);
return new MemoryStream(Convert.FromBase64String(reponseObject.Content));
}
}
}
}
and than client goes to this view but needs to wait for previous call to finish.
async public Task<ActionResult> ReviewDetails(int id)
{
return View();
}
Why does asp framework waits for await line to finish before it starts producing view for next url that client requested?
In ASP.NET, await yields to the thread pool, not the HTTP client.
Remember, your web app is serving HTTP responses to HTTP requests. Generally speaking, a single HTTP request has a single HTTP response. Your web app can't return a response and then sometime later return another response. You can think of an await as an "asynchronous wait", and your method will asynchronously wait there, so it won't even get to the return Json(...) until after the await completes.
If you want to kick off an independent background process, then I recommend using asynchronous messaging, as described on my blog. It's complex, but it's necessary for reliable work. Alternatively, you could use something like a SPA and not return early at all - allow the user to change pages while the HTTP request is still in progress.

Issue with HttpClient.PostAsJsonAsync Not Working from ASPX

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.

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;
}
}

WebClient UploadStringTaskAsync fails with no exception

I am calling UploadStringTaskAsync on a restful Web API 2 post method I wrote and it is failing with no exceptions. If I change the call to be UploadString, it works as expected. I've tried a number of different approaches. With UploadStringTaskAsync attempt Fiddler does show the post being issued but with a content-length mismatch (see below). I am running this call from a class library included in a test console app. .Net 4.5.2 So far just running in debug mode from VS 2015. here's my code:
private async Task PostLoggingItem(SmgLoggingItem loggingItem)
{
try
{
//using (WebClient client = new WebClient())
//{
//WebClient client = new WebClient();
const string authToken = "mytoken";
loggingItem.AuthToken = Encryptor.GenerateSecurityToken(authToken);
client.Encoding = Encoding.UTF8;
//client.Credentials = CredentialCache.DefaultNetworkCredentials;
//client.UseDefaultCredentials = true;
client.Credentials = new NetworkCredential("user","mypwd","mydom");
// set content type to JSon
client.Headers.Add("Content-Type", "application/json");
var jsonItem = JsonConvert.SerializeObject(loggingItem);
var response = await client.UploadStringTaskAsync(new Uri(ConfigurationManager.AppSettings["WebLogAPI"]), jsonItem);
//string response = client.UploadString(new Uri(ConfigurationManager.AppSettings["SMGWebLogAPI"]), "POST", jsonItem);
string result = JsonConvert.DeserializeObject<string>(response);
if (result != "ok")
{
await SMTPSendEmailAsync.SendEmail("brownp#spectrummg.com", "logging failed WebAPI call",
"Error return from WebAPI call in PostLoggingItem");
}
return;
//}
}
catch (Exception e)
{
await SMTPSendEmailAsync.SendEmail("brownp#spectrummg.com", "logging failed WebAPI call",
"Exception in PostLoggingItem" + e.Message);
return;
}
}
You can see where I have commented out the working UploadString call. Also, I have a theory problem related to "lifetime" of the WebClient object, so played around with creating it in the method (see commented using), but now create it with the object instantiation to which method PostLoggingItem belongs.
here's fiddler:
I'd sure like to know why the Async does not work. Also, I have used aync methods and awaits all the way up the call tree - to no avail.

Get response from PostAsJsonAsync

I have this line of code
var response = new HttpClient().PostAsJsonAsync(posturi, model).Result;
The Called WebAPI controller returns a bool to make sure the object was saved, but how do I return that bool response?
Continue to get from content:
var httpClient = new HttpClient();
var response = httpClient.PostAsJsonAsync(posturi, model).Result;
bool returnValue = response.Content.ReadAsAsync<bool>().Result;
But, this is really naive approach for quick way to get result. PostAsJsonAsync and ReadAsAsync is not designed to do like this, they are designed to support async await programming, so your code should be:
var httpClient = new HttpClient();
var response = await httpClient.PostAsJsonAsync(posturi, model);
bool returnValue = await response.Content.ReadAsAsync<bool>();
Also, instead of using a flag to check whether an object is saved or not, you should make use of HTTP codes by returning 200 OK to determine that saving is successfully.
The accepted answer is technically correct but blocks the current thread on calls to .Result. If you are using .NET 4.5 or higher, you should avoid that in almost all situations. Instead, use the equivalent asynchronous (non-blocking) version:
var httpClient = new HttpClient();
var response = await httpClient.PostAsJsonAsync(posturi, model);
bool returnValue = await response.Content.ReadAsAsync<bool>();
Note that the method containing the above code needs to be marked async, and should itself be awaited.
Since its an Async operation don't immediately do .Result as its wrong
Instead you need to do it async by doing this:
var httpClient = new HttpClient()
var task = httpClient.PostAsJsonAsync(posturi, model)
.ContinueWith( x => x.Result.Content.ReadAsAsync<bool>().Result);
// 1. GETTING RESPONSE - NOT ASYNC WAY
task.Wait(); //THIS WILL HOLD THE THREAD AND IT WON'T BE ASYNC ANYMORE!
bool response = task.Result
// 2. GETTING RESPONSE - TASK ASYNC WAY (usually used in < .NET 4.5
task.ContinueWith( x => {
bool response = x.Result
});
// 3. GETTING RESPONSE - TASK ASYNC WAY (usually used in >= .NET 4.5
bool response = await task;
NOTE: I just wrote them in here, so I didnt actually test them but more or less that's what you want.
I hope it helps!
I used HttpStatusCode to check the result.
public HttpStatusCode PostStaffPositions(Foo foo)
{
string uri = myapiuri;
using (HttpClient httpClient = new HttpClient())
{
var response = httpClient.PostAsJsonAsync(uri, foo).Result;
return response.StatusCode;
}
}
And then in Controller check it like this:
HttpStatusCode update = staffrest.PostStaffPositions(foo);
if (update == HttpStatusCode.OK)
{
//Update Succeed
}
else
{
//Update Failed
}
If you call the generic version, it should give you back the bool:
var response = new HttpClient().PostAsJsonAsync<bool>(posturi, model).Result;
At least according to the docs.
It's July 2021 and I'm using .net 5 (namely the .net core 5).
I did not see any generic methods above in System.Net.Http. Now the code looks like this (tested):
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://localhost:44330/api/Book/Add");
var response = client.PostAsJsonAsync(client.BaseAddress,
JsonSerializer.Serialize(_teamSummaries));
MessageBox.Show(#"Result is " + JsonSerializer.Serialize(response));
var returnValue = response.Result.Content.ReadAsStringAsync();
MessageBox.Show(#"Return value is " + returnValue.Result);
}
There are also ReadAsStringAsync, ReadAsByteArrayAsync, ReadAsStream, ReadFromJsonAsync, ReadFromJsonAsync<T> (this method returns Task<T>).
But from the text meaning "ReadFromJsonAsync", I think the T is not the bool mentioned above, but a class that contains the bool member. If you want to return something like book, give it a try.
On the other hands, since code on the server looks like this(.net 5):
[HttpPost]
[Route("Add")]
public async Task<ActionResult<IEnumerable<Book>>> Add(string value)
{
var all = await _dbCollection.FindAsync(Builders<Book>.Filter.Empty);
return Ok("Everything is ok.");
}
So, if we want to return true by bool, we should return Ok(...). If we want to return false by bool, we should return something else. There are more than 20 other types of results, which contains much more information rather than just "false".

Categories