synchronous authorization in WinRt - c#

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 .

Related

Calling async method from Page_Load of webforms

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

Windows phone 8 RestSharp request. Async/await

I know it has been asked a lot, but my problem is, that my method won't wait for the request to be completet, even though i have implemented a TaskCompletionSource, which should have done the job, but it doesn't.
public DecksViewModel(bool local)
{
DList = new List<Deck>();
if (local)
InitializeLocalDeckList();
else
{
Dereffering();
}
}
public async void Dereffering()
{
var e = await InitilaizeWebDeckList();
List<DeckIn> decksIn = JsonConvert.DeserializeObject<List<DeckIn>>(e);
foreach (DeckIn d in decksIn)
{
Deck dadd = new Deck();
dadd.CardCount = 0;
dadd.Name = d.name;
dadd.PicturePath = d.image;
dadd.InstallDirectory = false;
DList.Add(dadd);
}
DataSource = AlphaKeyGroup<Deck>.CreateGroups(DList, System.Threading.Thread.CurrentThread.CurrentUICulture, (Deck s) => { return s.Name; }, true);
}
public Task<String> InitilaizeWebDeckList()
{
var tcs = new TaskCompletionSource<string>();
var client = new RestClient("blabla.com");
var request = new RestRequest("");
request.AddHeader("Authorization", "Basic blabla");
client.ExecuteAsync(request, response =>
{
test = response.Content;
tcs.SetResult(response.Content);
});
return tcs.Task;
}
So when I call the DecksViewModel constructor, I asyncally try to request the data from a webserver and fill the model.
The point is, that the corresponding view "doesn't wait" for the request to fill the model, so it's displayed empty.
I use the
List<AlphaKeyGroup<Deck>> DataSource
to fill a LongListSelector via DataBinding. But DataSource isn't yet set, when it is binded.
I hope you can help
You're calling an async method without awaiting it inside the constructor. That's why "it doesn't wait" (because it has nothing to wait on).
It's usually a bad idea to call an async method inside the constructor for that reason combined with the fact that constructors can't be async.
You should redesign your solution accordingly. An option is to have an async static method that creates an instance and awaits the procedure:
public static async Task CreateInstance(bool local)
{
var model = new DecksViewModel();
if (local)
{
await InitializeLocalDeckList();
}
else
{
await Dereffering();
}
}
That would allow you to not use async void which should only be used in UI even handlers.
You can read more about other options in Stephen Cleary's blog
You are using async void, which means nobody's gonna wait for that. It's just fire and forget.
I see some misunderstanding in the async keyword here:
Your code will only wait for the result of an async method, if you use await. Otherwise that call will just start the async method, but you don't know when it is actually gonna run.
You cannot use await in constructors though.

SOAP Client doesn't finish its job or maybe doesn't return anything?

I'm using SOAP Client in Windows RT, I'm using Windows 8.1 OS and VS 2013. Anyway, what I want to do is just a simple task which returns a some string values.
When I try to do await - async task it doesn't return anything or maybe it just simply loses itself trying to find the client. I couldn't find a problem.
I added service reference , when I look at it in Object Browser there doesn't seem a problem. I'm stuck any idea why it's happening?
Here's my code:
using Namespace.InfoGetter;
private void btn_Click(object sender, RoutedEventArgs e)
{
Info info = GetInfo("en-US");
txtInfo.Text = info.Result.Value;
}
async Task<Info> GetInfo(string culture)
{
InfoSoapClient client = new InfoSoapClient();
Task<InfoResponse> info = client.GetInfoAsync(culture); <<<<<<<<<<<
Info result = await info;
return result;
}
When debug comes to the line (which I put <<<) client.GetInfoAsync(culture) doesn't return anything and the method ends there too. What to do?
As your code example isn't accurate, i assume what is happening is that you have a deadlock, since you block on info.Result while your await in GetInfo is trying to marshal work back to your UI thread.
We're going to add the async keyword to your buttons click event handler and await on GetInfoAsync
Try this:
private async void btn_Click(object sender, RoutedEventArgs e)
{
Info info = await GetInfoAsync("en-US");
textInfo.Text = info.Value
}
private Task<Info> GetInfoAsync(string culture)
{
InfoSoapClient client = new InfoSoapClient();
return client.GetInfoAsync(culture);
}
Note i added the Async suffix to your GetInfo method to follow the TAP convention and removed the async keyword from GetInfoAsync as you don't really need to generate the extra state machine as all you do is return is return the result and not do additional work with it.

WebClient DownloadStringAsync blocked - never finished

I have specific problem with WebClient in my Windows Phone app (using MVVM)
private string _lastCurrencyRatesJson;
private bool _lastCurrencyRatesJsonLoaded = false;
private void GetLastCoursesFromApiAsync()
{
var uri = new Uri(string.Format(OperationGetLastCourses, AppSettings.ApiEndpoint, AppSettings.ApiKey));
var client = new WebClient { Encoding = Encoding.UTF8 };
client.DownloadStringCompleted += client_DownloadStringCompleted;
client.DownloadStringAsync(uri);
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
_lastCurrencyRatesJson = e.Result;
_lastCurrencyRatesJsonLoaded = true;
}
public List<CurrencyRate> GetLastCourses()
{
var worker = new Thread(GetLastCoursesFromApiAsync);
worker.Start();
while (!_lastCurrencyRatesJsonLoaded)
{
}
.....
The problem is that client_DownloadStringCompleted is never fired BUT when I change GetLastCourses this way:
public List<CurrencyRate> GetLastCourses()
{
var worker = new Thread(GetLastCoursesFromApiAsync);
worker.Start();
// whetever here, but any while...
client_DownloadStringCompleted is fired and data are obtained. It means, connectivity is ok.
I had very similar problems with DownloadStringTaskAsyn. Example:
private async Task<string> GetCoursesForDayFromApiAsJson(DateTime date)
{
var uri = new Uri(string.Format(OperationGetCoursesForDay, AppSettings.ApiEndpoint, AppSettings.ApiKey, date.ToString(DateFormat)));
var client = new WebClient { Encoding = Encoding.UTF8 };
return await client.DownloadStringTaskAsync(uri);
}
Again, at the line with await is application waiting for the data but the DownloadStringTaskAsync is never finished and my UI is still loading.
Any ideas what could be wrong?
SITUATION ONE DAY AGO
So, it looks that WP application is working just with one thread. It means, current thread have to be "finished" and then is DownloadStringTaskAsync finished and the code under the await executed. When I want to work with Task.Result I can not. Never.
When I create another Thread and I am trying to wait for thread completetion (using Join()), created Thread is never finsihed and the code after Join() is never executed.
There is any example on the Internet and I absolutely don't know, why exists some DownloadStringTaskAsync when it is not applicable.
You're blocking the UI thread by your while loop and at the same time, the DownloadStringCompleted event wants to execute on the UI loop. This causes a deadlock, so nothing happens. What you need to do is to let GetLastCourses() return (and whatever method calls that), so that the event handler can execute. This means that the code that handles the results should be in that event handler (not in GetLastCourses()).
With async-await, you didn't provide all of your code, but it's likely that you're encountering pretty much the same issue by calling Wait() or Result on the returned Task. If replace that with await, you code will work. Though that requires you to make all your code from GetCoursesForDayFromApiAsJson() up async.
I'd recommend to use the HttpClient class from Microsoft NuGet package and use the async/await downloading pattern rather than using event-based WebClient class:
Uri uri = new Uri(string.Format(OperationGetLastCourses, AppSettings.ApiEndpoint, AppSettings.ApiKey));
using (HttpClient client = new HttpClient())
{
string result = await client.GetStringAsync(uri);
}

Login page to call a WCF service and get a response when done ASYNC

Well... I have a Login page and a WCF implanting the Event Based Async pattern. Eventually what I need to do here is to make my async call to the WCF method and the execution should wait for the response before continuing with the authentication or not and then redirect.
I am developing on WP8 and I call my WCF this way:
Login.xaml.cs
private async void SignIn_Click(object sender, EventArgs e)
{
await App.Instance.StaticServiceData.LoadUser(App.Instance.User);
LoginSuccessFail();
}
WCF_StaticDataService.cs
public async Task LoadUser(User user)
{
var client = new BMAStaticDataService.StaticClient();
client.AuthenticateUserAsync(user);
client.AuthenticateUserCompleted += async (o,e) => {
try
{
await UpdateCacheUserData(existing);
if (existing.UserId > 0)
{
App.Instance.User.UserId = existing.UserId;
App.Instance.User.Email = existing.Email;
App.Instance.IsUserAuthenticated = true;
}
else
{
App.Instance.IsUserAuthenticated = false;
throw new Exception("User has no authentication");
}
}
catch (Exception){throw;}
}
I want to call the LoginSuccessFail(); method and then navigate to the appropriate page only after the WCF call is completed.
Note that I wouldn't like to put my navigation aware code in the Service class and the AuthenticateUserCompleted event since it is not its job to handle this.
Eventually I would like to receive a callback or feedback or whatever in my Login.xaml.cs after the service call is done, successfully or not.
Hope my info is enough. Otherwise please advise to provide further clarification.

Categories