The Xamarin.Auth component is a huge time saver when interacting with services like Twitter and others that require authentication. In most cases, Xamarin.Auth makes authentication as simple as initializing an authenticator and then dealing with success or failure.
As an example, here’s the code to do Twitter authentication with Xamarin.Auth
void DoMyTwitterAuth() { var auth = new OAuth1Authenticator( Constants.TwitterConsumerKey, Constants.TwitterConsumerSecret, new Uri("https://api.twitter.com/oauth/request_token"), new Uri("https://api.twitter.com/oauth/authorize"), new Uri("https://api.twitter.com/oauth/access_token"), new Uri("http://twitter.com")); auth.Completed += (sender, e) => { if(e.IsAuthenticated) { var account = e.Account; // Do success work } }; auth.Error += (sender, e) => { // Do Error work }; // iOS var ui = auth.GetUI(); PresentViewController(UI, true, null); // Android //var ui = auth.GetUI(this); //StartActivity(UI) }
Authenticating against any remote service requires communicating over the Internet which, of course, involves an indeterminate time delay. As a result, the auth.Completed or auth.Error event handlers get called asynchronously after some significant (in computer terms) delay.
We know that writing apps that use traditional asynchronous techniques can be complicated. To deal with this scenario, .NET provides the Task<T> class along with the async and await keywords. With these tools we get to code things using traditional linear programming techniques leaving the asynchronous details to .NET.
What Simpler Looks Like
If authentication was setup to use Task<T> we could write our authentication code something like this.
async void DoMyTwitterAuth() { try { var account = await AuthHelper.OAuth1( Constants.TwitterConsumerKey, Constants.TwitterConsumerSecret, new Uri("https://api.twitter.com/oauth/request_token"), new Uri("https://api.twitter.com/oauth/authorize"), new Uri("https://api.twitter.com/oauth/access_token"), new Uri("http://twitter.com")); // Do success work } catch (Exception ex) { // Do error work } }
That is so much simpler to work with than having to explicitly handle the callbacks in separate methods or lambda expressions.
The problem, of course, is that Xamarin.Auth doesn’t support that async/await programming style.
But! We Can Fix That
We can code up an AuthHelper.OAuth1 implementation that translates the Xamarin.Auth callbacks into Task<T> that’ll allow us to use async/await.
Here’s the OAuth1 implementation…
using Xamarin.Auth; using System.Threading.Tasks; // other usings elided for clarity static class AuthHelper { public static Task<Account>OAuth1( string consumerKey, string consumerSecret, Uri requestTokenUrl, Uri authorizeUrl, Uri accessTokenUrl, Uri callbackUrl) { TaskCompletionSource<Account> tcs = new TaskCompletionSource<Account>(); var auth = new OAuth1Authenticator( consumerKey, consumerSecret, requestTokenUrl, authorizerl, accessTokenUrl, callbackUrl); auth.Completed += (sender, e) => { tcs.SetResult(e.IsAuthenticated ? e.Account : null); }; auth.Error += (sender, e) => { tcs.SetException(e.Exception); }; // iOS var ui = auth.GetUI(); someViewController.PresentViewController(ui, true, null); // Android //var ui = auth.GetUI(someActivity); //someActivity.StartActivity(ui); return tcs.Task; } }
Now That’s Better!
With that little helper method, we can now do our authentication code using a simple linear programming style with the help of async/await.
try { var account = await AuthHelper.OAuth1(...); // do success work } catch(Exception ex); // do error work }
The key to making this work is the TaskCompletionSource. It allows us to easily translate non-Task style asynchronous work to Task-style. Basically it creates a Task<T> instance that can be await’ed on. When the work completes we call the SetResult or SetException methods and the TaskCompletionSource handles the Task signalling details.
We use this technique at Spectafy and it has made our Xamarin.Auth programming so much easier.