Calling async method from Page_Load of webforms - c#

Here is a question related to my question i found, which did not work.
In my Page load method of web forms I want to call async method
void Page_Load(object sender, EventArgs e)
I want to call async method because I want to be able to call the GetUserInfoAsync method of IdentityModel
This is what I have
protected void Page_Load(object sender, EventArgs e)
{
var token = HttpContext.Current.Request.Headers.Get("Authorization");
GetUserClaims(token).Wait();
}
public async Task GetUserClaims(string token)
{
var client = new HttpClient();
var response = await client.GetUserInfoAsync(new UserInfoRequest
{
Address = "https://localhost:44367/connect/userinfo",
Token = token,
});
var result = response.Claims;
}
Current problem is I never reach result = response.claims part.
GetUserClaims(token).Wait();
was based upon the answer to the question I linked above.
The other option I tried was use the PageAsyncTask and RegisterAsyncTask as mentioned in one of the option in the answer.
PageAsyncTask t = new PageAsyncTask(GetUserClaims(token));
but I get red squiggly thing which complains saying
cannot convert from System.Threading.Task.Task to System.Func<System.Threading.Task.Task>

Actually this helped
protected void Page_Load(object sender, EventArgs e)
{
var token = HttpContext.Current.Request.Headers.Get("Authorization");
PageAsyncTask t = new PageAsyncTask(() => GetUserClaims(token));
// Register the asynchronous task.
Page.RegisterAsyncTask(t);
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
//GetUserClaims(token).ConfigureAwait(false).GetAwaiter().GetResult();
}

If you absolutely can't make the Page_Load event handler async void, as is suggested by the linked question, then the proper way would be:
GetUserClaims(token).ConfigureAwait(false).GetAwaiter().GetResult();
To avoid the deadlock which happens when you call Wait().
You would also need to add .ConfigureAwait(false) to all nested async calls to ensure that the execution resumes in the same context:
UserInfoResponse response = await client.GetUserInfoAsync(new UserInfoRequest
{
Address = "https://localhost:44367/connect/userinfo",
Token = token,
}).ConfigureAwait(false);

Related

What is causing the deadlock?

I know this is not using the proper form, but can someone tell me why the first code snippet works and the 2nd causes a deadlock?
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = DownloadStringV3("https://www.google.com");
}
public string DownloadStringV3(String url)
{
var resp = new HttpClient().GetAsync(url).Result;
return resp.Content.ReadAsStringAsync().Result;
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = DownloadStringV3("https://www.google.com").Result;
}
public async Task<string> DownloadStringV3(String url)
{
var resp = await new HttpClient().GetAsync(url);
return await resp.Content.ReadAsStringAsync();
}
Different synchronization contexts? This is using .NET 4.8
Every time you await something, you say, I am temporary done here, give some other thread a chance to execute and then continue from here, when the async task is completed.
So in your case await new HttpClient().GetAsync(url) switches the the ui thread and waiting for DownloadStringV3("https://www.google.com").Result be done, which will never be the case, because we do never execute return await resp.Content.ReadAsStringAsync().
Thats why you should do async all the way to the root and never call Result.
The first code works, because you block on the UI thread and don't try to switch to another thread, while waiting for it.
To make the second one working you need to:
private async void button1_Click(object sender, EventArgs e)
{
// make with try catch sure, you catch any error, async void is special. Better is async Task
textBox1.Text = await DownloadStringV3("https://www.google.com");
}
public async Task<string> DownloadStringV3(String url)
{
var resp = await new HttpClient().GetAsync(url);
return await resp.Content.ReadAsStringAsync();
}

Xamarin.Forms GetAsync stops debugging without error

My MainPage code-behind:
private void Button_Clicked(object sender, EventArgs e)
{
Query().Wait();
App.Current.MainPage = new Categories();
}
public async Task Query()
{
restaurantsClient = (App.Current as App).restaurantsClient;
try
{
var restaurantsNames = await restaurantsClient.GetCatalogsAsync(1);
}
catch (Exception ex)
{
var x = 0;
}
}
I tried this code too but didn't work, happens the same problem:
async static Task GetRequest(String URL)
{
using (HttpClient client = new HttpClient())
{
// As soon as I try to step over (or even into) this next line, it crashes.
using (HttpResponseMessage response = await client.GetAsync(URL))
{
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync();
Console.WriteLine(data);
}
}
}
}
Rest-API in C#:
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
When the project reach this line it just die without showing any error.
If I do it in the browser it works.
The API is running locally in my PC (Im using Conveyor to expose the API).
Ok I make a video to see better what Im talking about:
https://youtu.be/ONKTipPsEXI
As you can see after I click Next Step in response line stop executing the rest of the code.
That's because you're using .Wait() of a Task on the UI thread (Button.Clicked event is handled on the UI thread) causing a deadlock. The task is waiting for the UI thread to give it control and the UI thread is waiting for the task to complete. The solution to this is to add async modifier to your event handler and use await Query() instead of Query().Wait().
private async void Button_Clicked(object sender, EventArgs e)
{
await Query();
App.Current.MainPage = new Categories();
}
I'd also recommend reading this article by Stephen Cleary about this matter. Moreover, he's made a fabulous series (A Tour of Task) about C# tasks in general.
UPDATE:
After OP's question update and discussion in this answer's comments; he thinks that there's a problem because he can reach the end of GetCatalogsAsync(int) before the end of GetCatalogsAsync(int, CancellationToken). That's completely natural and is to be expected. Solution:
public async System.Threading.Tasks.Task<CatalogsInCategory> GetCatalogsAsync(int id)
{
return await GetCatalogsAsync(id, System.Threading.CancellationToken.None);
}

Error with HttpClient

I have been working on a simple c# application that uses rest and Azure SQL Database. My app has two buttons one for saving new names and the second for showing them. the later doesn't react when i press it and i get the following error related to these parts GetRequest(); PostRequest(jsonPost);
private void Btn_Click(object sender, EventArgs e)
{
GetRequest();
}
private void Btn_Click(object sender, EventArgs e)
{
User user = new User(0, firstnameText.Text);
JavaScriptSerializer java = new JavaScriptSerializer();
String jsonPost = java.Serialize(user);
PostRequest(jsonPost);
}
}
Severity Code Description Project File Line Suppression State Detail Description
Warning CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. PersonRegister C:\Users\User\Downloads\RestSolution\RestSolution\PersonRegister\Form1.cs 86 Active The current method calls an async method that returns a Task or a Task and doesn't apply the await operator to the result. The call to the async method starts an asynchronous task. However, because no await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't what you expect. Usually other aspects of the calling method depend on the results of the call or, minimally, the called method is expected to complete before you return from the method that contains the call.
An equally important issue is what happens to exceptions that are raised in the called async method. An exception that's raised in a method that returns a Task or Task is stored in the returned task. If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown.
As a best practice, you should always await the call.
You should consider suppressing the warning only if you're sure that you don't want to wait for the asynchronous call to complete and that the called method won't raise any exceptions. In that case, you can suppress the warning by assigning the task result of the call to a variable.
Although the advice to always return Task from an async method, this is not possible for UI event handlers. As such you should rewrite your handler like this:
private async void Button1_Click(object sender, EventArgs e)
{
await GetRequest();
}
private async void Button2_Click(object sender, EventArgs e)
{
Person p = new Person(0, nameText.Text);
JavaScriptSerializer js = new JavaScriptSerializer();
String jsonPost = js.Serialize(p);
await PostRequest(jsonPost);
}
See here for more info.
Also, as an aside, you should declare one static instance of HttpClient for the entire application (as per MSDN docs).

Problems with HttpClient on WP8

Please tell me why it works only once?
I want to create a button to update the time, but my app only shows me the first time I got
public async void q()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://cleverapps.ru/wp.php");
string getResponsestring = await response.Content.ReadAsStringAsync();
MessageBox.Show(getResponsestring);
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
q();
}
This probably happens because caching is enabled by default.
Try adding the following line before making the GetAsync call:
client.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow;

synchronous authorization in WinRt

I am basically trying to run my authorization process for my WinRt app synchronously, but everything I've tried appears to deadlock the app after authorization on the MainPage, preventing navigation to the HomePage. Can't seem to figure it out. Here is my code without modifications, which works perfectly fine asynchronously below. How can I make this work synchronously:
Class:
public async void InitializeTwitterAsnc()
{
WinRtAuthorizer authorizer = null;
authorizer = new WinRtAuthorizer()
{
Credentials = new LocalDataCredentials()
{
ConsumerKey = "blah379",
ConsumerSecret = "blah123"
},
UseCompression = true,
Callback = new Uri("http://blah.com")
};
if(!authorizer.IsAuthorized)
{
await authorizer.AuthorizeAsync();
}
// set the twitter credential fields
await Task.Run
(() =>
{
twitterName = authorizer.Credentials.ScreenName;
twitterId = authorizer.Credentials.UserId;
accessToken = authorizer.Credentials.AccessToken;
oAuthToken = authorizer.Credentials.OAuthToken;
this.TwitterContext = new TwitterContext(authorizer);
});
}
code that calls the method from MainPage.xaml.cs:
private void StartTwitterLogin(object sender, RoutedEventArgs e)
{
// start the twitter authorization
TwitterAuth twitAuth = new TwitterAuth();
twitAuth.InitializeTwitterAsnc();
this.Frame.Navigate(typeof (HomePage));
}
You can't. Asynchronouse APIs are only meant to be run asynchronously and if you try to force your thread to wait for the result - you will often get a deadlock since the APIs themselves often need to run something on the thread you are blocking. You shouldn't try to fight it and rather think what the actual problem you are trying to solve is.
In your case you should change the signature of your method from
public async void InitializeTwitterAsnc()
to
public async Task InitializeTwitterAsnc()
so that it can be awaited and then await it here:
private async Task StartTwitterLogin(object sender, RoutedEventArgs e)
{
// start the twitter authorization
TwitterAuth twitAuth = new TwitterAuth();
await twitAuth.InitializeTwitterAsnc();
this.Frame.Navigate(typeof (HomePage));
}
So ultimately, my solution was to handle the navigation inside the async twitAuth.InitializeTwitterAsync() method. In order for the navigation to work, I had to create a static frame property in the app.xaml.cs that I could use in my custom class for navigation. See this link WinRt page navigaiton .

Categories