Async WebRequest freezes application - c#

I am building an app that will have registration option and I've made a method for checking whether username is available or not that is async. Method connects via WebRequest to my PHP/MySQL API and retrieves if username is taken or not.
However whenever I try to run this the code blocks on line
var response = await webRequest.GetResponseAsync();
and whole application just freezes. Doing this same method synchronously works fine though.
Whole method:
async public Task<UsernameAvailable> usernameAvailable()
{
try
{
token = "token=single";
function = "&function=checkUser";
string param = "&param=" + User.username;
string result = "";
var webRequest = WebRequest.Create(#"http://" + APIURL + token + function + param);
var response = await webRequest.GetResponseAsync(); //troubled line
var content = response.GetResponseStream();
StreamReader reader = new StreamReader(content);
result = reader.ReadLine();
if (result == "0")
{
state = "Username is available.";
return UsernameAvailable.Available;
}
else
{
state = "Username is not available.";
return UsernameAvailable.NotAvailable;
}
}
catch
{
state = "Error checking for username.";
return UsernameAvailable.Error;
}
}

I'm going to go on a wild guess here and say that higher up the callstack you're calling usernameAvailable like this:
usernameAvailable().Result
Which is blocking on async code, causing your app to deadlock. This is why you shouldn't block on async code. The reason your answer works is because using ConfigureAwait(false) prevents the synchronization context from following to the continuation, but that is just a dirty workaround which covers up the actual problem of your code.
Instead of doing that, you should also use an async event handler and await on your method as well:
public async void SomeEventHandler(object sender, EventArgs e)
{
await usernameAvailable();
}
Side note - Async methods should have the Async postfix added to them, so your method should actually be named UsernameAvaliableAsync()

Adding .ConfigureAwait(false) to the troubled line fixed the issue and everything works fine now!
old:
var response = await webRequest.GetResponseAsync();
fixed:
var response = await webRequest.GetResponseAsync().ConfigureAwait(false);

Related

call HttpClient GetAsync but app freezes seconds and works as sync mode

Below is my code to get an HTML page
public static async Task<string> GetUrltoHtml(string url)
{
string s;
using (var client = new HttpClient())
{
var result = client.GetAsync(url).Result;
//Console.WriteLine("!!!"+result.StatusCode);
s = result.Content.ReadAsStringAsync().Result; //break point
}
return s;
}
the line
var result = client.GetAsync(url).Result;
causes app freeze seconds and work as sync mode
Your comment welcome
According to the docs
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
So getting Result is a blocking action. You should use await instead.
s = await result.Content.ReadAsStringAsync();
(Result is helpful when the result is ready and you just want to get it. Or in some cases you want to block the thread (but it's not recommended).)

Retrieving records from Azure Storage account table using c# while developing cross platform app using xamarin giving error

Retrieving records from Azure Storage account table using c# while developing cross platform app using xamarin giving error.
await tbl.ExecuteAsync(retrieveOperation);
I AM FOLLOWING THIS LINK!
This code gives exception (Time awaiting and Async error using storageexception) when ILogin() is executed separately i.e not through the Logmein().
When I run Logmein() with the code in current form, nothing happens i.e not exception error occurs.
When i use task.Wait(); exception/error occurs related to wait. I'll try to provide exception details.
My code is here
private void Logmein()
{
var task = Task.Run(async () => { await Ilogin(); });// Nothing happens by this code
//task.Wait(); It gives error/Exception.}
private static async Task Ilogin()
{
// Rest of the code is right (TESTED)
Microsoft.WindowsAzure.Storage.Table.CloudTable table = tableClient.GetTableReference("user");
Entry uname = new Entry();
Entry pword = new Entry();
Label linfo = new Label();
string userid = uname.Text.ToString();
string passcode = pword.Text.ToString();
Reg signuser = new Reg(userid);
TableOperation retrieveOperation = TableOperation.Retrieve<Reg>("regform", userid);
TableResult retrievedResult = await tbl.ExecuteAsync(retrieveOperation); //This AWAIT is making trouble
Reg loginuser = (Reg)retrievedResult.Result;
string u1 = loginuser.username.ToString();
string p1 = loginuser.password.ToString();
if (u1 == userid && p1 == passcode)
{
linfo.Text = "Login Successful";
//await Navigation.PushAsync(new MainPage());
}
else
{
linfo.Text = "Invalid Username or Password";
}
}
// here is my exception handling code
catch (Exception ex)
{
linfo.Text = "login Login Error" + ex.Message + ex.StackTrace + ex.HelpLink + ex.Source;
}
THANKS in advance.
Either go asynchronous all the way or synchronous all the way. Try to avoid mixing the two.
Task Ilogin() is an asynchronous method while void Logmein() is not
it should be made async and then awaited
private async Task Logmein() {
await Ilogin();
}
There is no need for the Task.Run with fire and forget methods as their exception cannot be caught. Plus mixing blocking calls like Task.Wait() and Task.Result can lead to deadlocks.
if Logmein() needs to be invoked try putting it in an event handler, which would allow for async void so that it can be awaited.
private async void SomeHandler(object sender, EventArgs args) {
await Logmein();
}
If that is the case you can avoid Logmein() and await Ilogin() directly.
Reference Async/Await - Best Practices in Asynchronous Programming

DbContext getting disposed too early within Async method

When converting an existing synchronous method to async, I accidentally used "async void" on one of the methods, which resulted in some unexpected behavior.
Below is a simplified example of the kind of change I had actually performed,
public IActionResult Index()
{
var vm = new ViewModel();
try
{
var max = 0;
if (_dbContext.OnlyTable.Any())
{
max = _dbContext.OnlyTable.Max(x => x.SomeColumn);
}
_dbContext.Add(new TestTable() { SomeColumn = max + 1 });
_dbContext.SaveChanges();
MakePostCallAsync("http:\\google.com", vm);
if (!string.IsNullOrEmpty(vm.TextToDisplay))
{
vm.TextToDisplay = "I have inserted the value " + newmax + " into table (-1 means error)";
}
else
{
vm.TextToDisplay = "Errored!";
}
}
catch (Exception ex)
{
vm.TextToDisplay = "I encountered error message - \"" + ex.Message + "\"";
}
return View("Index", vm);
}
private async void MakePostCallAsync(string url, ViewModel vm)
{
var httpClient = new HttpClient();
var httpResponse = await httpClient.PostAsync("http://google.com", null).ConfigureAwait(true);
newmax = _dbContext.OnlyTable.Max(x => x.SomeColumn);
}
The issue is that, the MakePostCallAsync() method, when trying to query the database using DbContext, throws an exception saying DbContext is already disposed.
_dbContext in the example is injected using ASP .Net Core's DI (through AddDbContext() extension) with its default scope (Scoped).
I fail to and need help understand the following,
why the DB context is disposed even before the request is served, while Scoped object's lifetime should be the entire duration of the current request
Even though I have used ConfigureAwait(true) (which explicitly means that once the awaited method returns MakePostCallAsync() should continue in Request context?) - this doesn't seem to be happening
In the actual code, this was fixed once I made all the methods async (all the way up to controller) - in the repro I have shared, even that doesn't help prevent the exception - why is it so, how do I solve this?
Repro is available in https://github.com/jjkcharles/SampleAsync
You should never use async void unless you are writing a event handler. If you want to use async/await you need to go all the way up the call stack till you get to return a Task<IActionResult>
public async Task<IActionResult> Index()
{
var vm = new ViewModel();
try
{
var max = 0;
if (_dbContext.OnlyTable.Any())
{
max = _dbContext.OnlyTable.Max(x => x.SomeColumn);
}
_dbContext.Add(new TestTable() { SomeColumn = max + 1 });
_dbContext.SaveChanges();
await MakePostCallAsync("http:\\google.com", vm);
if (!string.IsNullOrEmpty(vm.TextToDisplay))
{
vm.TextToDisplay = "I have inserted the value " + newmax + " into table (-1 means error)";
}
else
{
vm.TextToDisplay = "Errored!";
}
}
catch (Exception ex)
{
vm.TextToDisplay = "I encountered error message - \"" + ex.Message + "\"";
}
return View("Index", vm);
}
private async Task MakePostCallAsync(string url, ViewModel vm)
{
var httpClient = new HttpClient();
var httpResponse = await httpClient.PostAsync("http://google.com", null).ConfigureAwait(true);
newmax = _dbContext.OnlyTable.Max(x => x.SomeColumn);
}
It seems to me you have some trouble understanding how to use async-await, because I see several major errors in your program.
This article, written by the ever so helpful Stephen Cleary helped me to understand how to use it properly.
Every function that wants to use async-await has to return Task instead of void and Task<TResult> instead of TResult. The only exception to this rule are event handlers that are not interested in the result of the actions.
So first change Index such that it returns a Task<IActionResult>. Once you've done this, your compiler will probably warn you that you forgot to await somewhere inside your Index function.
If you call an async function, you don't have to wait for it to finish, you can do other useful stuff, that will be performed whenever the async function has to await for something. But before you can use any result of the async function you have to await until it is ready:
var taskMakePostCall = MakePostCallAsync(...)
// if you have something useful to do, don't await
DoSomethingUseful(...);
// now you need the result of MakePostCallAsync, await until it is finished
await taskMakePostCall;
// now you can use the results.
If your MakePostCallAsync would have returned something, for instance an int, the return value would have been Task<int> and your code would have been:
Task<int> taskMakePostCall = MakePostCallAsync(...)
DoSomethingUseful(...);
int result = await taskMakePostCall;
If you don't have something useful to do, just await immediately:
int result = await MakePostCallAsync(...);
The reason for your exception is that your MakePostCallAsync is not finished completely before you somewhere Dispose your dbContext, probably via a using statement. After adding this await before returning you are certain that MakePostCallAsync is completely finished before returning Index()
In your example you are not awaiting your call to MakePostCallAsync("http:\\google.com", vm). This means the request continues execution immediately and it eventually executes the code that disposes of your _dbContext, presumably while MakePostCallAsync is still waiting for the HTTP client to return a response. Once the HTTP client does return a response your MakePostCallAsync tries to call newmax = _dbContext.OnlyTable.Max(x => x.SomeColumn) but your request has already been handled and your DB context disposed of by then.

Calling Async in a Sync method

I've been reading examples for a long time now, but unfortunately I've been unable to apply the solutions to the code I'm working with. Some quick Facts/Assorted Info:
1) I'm new to C#
2) The code posted below is modified from Amazon Web Services (mostly stock)
3) Purpose of code is to compare server info to offline already downloaded info and create a list of need to download files. This snip is for the list made from the server side, only option with AWS is to call async, but I need this to finish before moving forward.
public void InitiateSearch()
{
UnityInitializer.AttachToGameObject(this.gameObject);
//these are the access key and secret access key for credentials
BasicAWSCredentials credentials = new BasicAWSCredentials("secret key", "very secret key");
AmazonS3Config S3Config = new AmazonS3Config()
{
ServiceURL = ("url"),
RegionEndpoint = RegionEndpoint.blahblah
};
//Setting the client to be used in the call below
AmazonS3Client Client = new AmazonS3Client(credentials, S3Config);
var request = new ListObjectsRequest()
{
BucketName = "thebucket"
};
Client.ListObjectsAsync(request, (responseObject) =>
{
if (responseObject.Exception == null)
{
responseObject.Response.S3Objects.ForEach((o) =>
{
int StartCut = o.Key.IndexOf(SearchType) - 11;
if (SearchType == o.Key.Substring(o.Key.IndexOf(SearchType), SearchType.Length))
{
if (ZipCode == o.Key.Substring(StartCut + 12 + SearchType.Length, 5))
{
AWSFileList.Add(o.Key + ", " + o.LastModified);
}
}
}
);
}
else
{
Debug.Log(responseObject.Exception);
}
});
}
I have no idea how to apply await to the Client.ListObjectsAsync line, I'm hoping you all can give me some guidance and let me keep my hair for a few more years.
You can either mark your method async and await it, or you can call .Wait() or .Result() on the Task you're given back.
I have no idea how to apply await to the Client.ListObjectsAsync line
You probably just put await in front of it:
await Client.ListObjectsAsync(request, (responseObject) => ...
As soon as you do this, Visual Studio will give you an error. Take a good look at the error message, because it tells you exactly what to do next (mark InitiateSearch with async and change its return type to Task):
public async Task InitiateSearchAsync()
(it's also a good idea to add an Async suffix to follow the common pattern).
Next, you'd add an await everywhere that InitiateSearchAsync is called, and so on.
I'm assuming Client.ListObjectsAsync returns a Task object, so a solution for your specific problem would be this:
public async void InitiateSearch()
{
//code
var collection = await Client.ListObjectsAsync(request, (responseObject) =>
{
//code
});
foreach (var item in collection)
{
//do stuff with item
}
}
the variable result will now be filled with the objects. You may want to set the return type of InitiateSearch() to Task, so you can await it too.
await InitiateSearch(); //like this
If this method is an event handler of some sort (like called by the click of a button), then you can keep using void as return type.
A simple introduction from an unpublished part of the documentation for async-await:
Three things are needed to use async-await:
The Task object: This object is returned by a method which is executed asynchronous. It allows you to control the execution of the method.
The await keyword: "Awaits" a Task. Put this keyword before the Task to asynchronously wait for it to finish
The async keyword: All methods which use the await keyword have to be marked as async
A small example which demonstrates the usage of this keywords
public async Task DoStuffAsync()
{
var result = await DownloadFromWebpageAsync(); //calls method and waits till execution finished
var task = WriteTextAsync(#"temp.txt", result); //starts saving the string to a file, continues execution right await
Debug.Write("this is executed parallel with WriteTextAsync!"); //executed parallel with WriteTextAsync!
await task; //wait for WriteTextAsync to finish execution
}
private async Task<string> DownloadFromWebpageAsync()
{
using (var client = new WebClient())
{
return await client.DownloadStringTaskAsync(new Uri("http://stackoverflow.com"));
}
}
private async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath, FileMode.Append))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
}
Some thing to note:
You can specify a return value from an asynchronous operations with Task. The await keyword waits till the execution of the method finishes, and returns the string.
the Task object contains the status of the execution of the method, it can be used as any other variable.
if an exception is thrown (for example by the WebClient) it bubbles up at the first time the await keyword is used (in this example at the line string result (...))
It is recommended to name methods which return the Task object as MethodNameAsync
For more information about this take a look at http://blog.stephencleary.com/2012/02/async-and-await.html.

Reading the response from HttpClient.GetStringAsync

I am working on a Windows Universal app using the new runtime for Windows Phone/Store apps. I am sending a request to a server using the following code and expecting a HTML response back. However when I return the string and display it in the UI, it just says:
"System.Threading.Tasks.Task'1[System.String]"
It's not showing me the actual HTML/XML that should be returned. When I use the same URL in a normal Windows Forms app, it's returning the data I expect but the code I use there is different due to it being Win32 not WinRT/this new RT.
Here's my code. I suspect I am not returning the data in the right format or something but I don't know what I should be doing.
var url = new Uri("http://www.thewebsitehere.com/callingstuff/calltotheserveretc");
var httpClient = new HttpClient();
try
{
var result = await httpClient.GetStringAsync(url);
string checkResult = result.ToString();
httpClient.Dispose();
return checkResult;
}
catch (Exception ex)
{
string checkResult = "Error " + ex.ToString();
httpClient.Dispose();
return checkResult;
}
I don't think the problem is in this code snippet but in the caller. I suspect this code is in a method returning a Task (correct so that the caller can wait for this method's HttpClient call to work) but that the caller isn't awaiting it.
The code snippet looks correct and essentially the same as in the docs at https://msdn.microsoft.com/en-us/library/windows/apps/windows.web.http.httpclient.aspx . GetStringAsync returns a Task. The await will handle the Task part and will return a string into var result. If you break inside the function and examine result or checkResult they'll be the desired strings.
The same thing needs to happen with the caller. If this is in a function
Task<string> GetData()
{
// your code snippet from the post
return checkResult; // string return is mapped into the Task<string>
}
Then it needs to be called with await to get the string rather than the task and to wait for GetData's internal await to finish:
var v = GetData(); // wrong <= var will be type Task<string>
var data = await GetData(); // right <= var will be type string
The only time you wouldn't await the Task is if you need to manipulate the Task itself and not just get the result.
The 'await' operator can only be used within an async method. Change its return type to Task<string> should resolve the problem. The try block should be something like this:
try
{
Task<string> t = httpClient.GetStringAsync(url);
string checkResult = t.Result;
httpClient.Dispose();
return checkResult;
}

Categories

Resources