In previous posts, I explained how to use LINQ to Twitter with Windows 8, but the example was a Twitter Search, which didn’t require authentication. Much of the Twitter API requires authentication, so this post will explain how you can perform OAuth authentication with LINQ to Twitter in a Windows 8 Metro-style application. Getting Started I have earlier posts on how to create a Windows 8 app and add pages, so I’ll assume it isn’t necessary to repeat here. One difference is that I’m using Visual Studio 2012 RC and some of the terminology and/or library code might be slightly different. Here are steps to get started: Create a new Windows metro style app, selecting the Blank App project template. Create a new Basic Page and name it OAuth.xaml. Note: You’ll receive a prompt window for adding files and you should click Yes because those files are necessary for this demo. Add a new Basic Page named TweetPage.xaml. Open App.xaml.cs and change !rootFrame.Navigate(typeof(MainPage)) to !rootFrame.Navigate(typeof(TweetPage)). Now that the project is set up you’ll see the reason why authentication is required by setting up the TweetPage. Setting Up to Tweet a Status In this section, I’ll show you how to set up the XAML and code-behind for a tweet. The tweet logic will check to see if the user is authenticated before performing the tweet. To tweet, I put a TextBox and Button on the XAML page. The following code omits most of the page, concentrating primarily on the elements of interest in this post: <StackPanel Grid.Row="1">
<TextBox Name="TweetTextBox" Margin="15" />
<Button Name="TweetButton" Content="Tweet"
Click="TweetButton_Click" Margin="15,0" />
</StackPanel>
Given the UI above, the user types the message they want to tweet, and taps Tweet. This invokes TweetButton_Click, which checks to see if the user is authenticated. If the user is not authenticated, the app navigates to the OAuth page. If they are authenticated, LINQ to Twitter does an UpdateStatus to post the user’s tweet. Here’s the TweetButton_Click implementation:
void TweetButton_Click(object sender, RoutedEventArgs e)
{
PinAuthorizer auth = null;
if (SuspensionManager.SessionState.ContainsKey("Authorizer"))
{
auth = SuspensionManager.SessionState["Authorizer"] as PinAuthorizer;
}
if (auth == null || !auth.IsAuthorized)
{
Frame.Navigate(typeof(OAuthPage));
return;
}
var twitterCtx = new TwitterContext(auth);
Status tweet = twitterCtx.UpdateStatus(TweetTextBox.Text);
new MessageDialog(tweet.Text, "Successful Tweet").ShowAsync();
}
For authentication, this app uses PinAuthorizer, one of several authorizers available in the LINQ to Twitter library. I’ll explain how PinAuthorizer works in the next section. What’s important here is that LINQ to Twitter needs an authorizer to post a Tweet.
The code above checks to see if a valid authorizer is available. To do this, it uses the SuspensionManager class, which is part of the code generated earlier when creating OAuthPage.xaml. The SessionState property is a Dictionary<string, object> and I’m using the Authorizer key to store the PinAuthorizer. If the user previously authorized during this session, the code reads the PinAuthorizer instance from SessionState and assigns it to the auth variable.
If the user is authorized, auth would not be null and IsAuthorized would be true. Otherwise, the app navigates the user to OAuthPage.xaml, which I’ll discuss in more depth in the next section.
When the user is authorized, the code passes the authorizer, auth, to the TwitterContext constructor. LINQ to Twitter uses the auth instance to build OAuth signatures for each interaction with Twitter. You no longer need to write any more code to make this happen. The code above accepts the tweet just posted in the Status instance, tweet, and displays a message with the text to confirm success to the user.
You can pull the PinAuthorizer instance from SessionState, instantiate your TwitterContext, and use it as you need. Just remember to make sure you have a valid authorizer, like the code above. As shown earlier, the code navigates to OAuthPage.xaml when a valid authorizer isn’t available. The next section shows how to perform the authorization upon arrival at OAuthPage.xaml.
Doing the OAuth Dance
This section shows how to authenticate with LINQ to Twitter’s built-in OAuth support. From the user perspective, they must be navigated to the Twitter authentication page, add credentials, be navigated to a Pin number page, and then enter that Pin in the Windows 8 application. The following XAML shows the relevant elements that the user will interact with during this process.
<StackPanel Grid.Row="2">
<WebView x:Name="OAuthWebBrowser" HorizontalAlignment="Left" Height="400"
Margin="15" VerticalAlignment="Top" Width="700" />
<TextBlock Text="Please perform OAuth process (above), enter Pin (below) when ready, and tap Authenticate:"
Margin="15,15,15,5" />
<TextBox Name="PinTextBox" Margin="15,0,15,15" Width="432"
HorizontalAlignment="Left" IsEnabled="False" />
<Button Name="AuthenticatePinButton" Content="Authenticate" Margin="15"
IsEnabled="False" Click="AuthenticatePinButton_Click" />
</StackPanel>
The WebView in the code above is what allows the user to see the Twitter authentication page. The TextBox is for entering the Pin, and the Button invokes code that will take the Pin and allow LINQ to Twitter to complete the authentication process.
As you can see, there are several steps to OAuth authentication, but LINQ to Twitter tries to minimize the amount of code you have to write. The two important parts of the code to make this happen are the part that starts the authentication process and the part that completes the authentication process. The following code, from OAuthPage.xaml.cs, shows a couple events that are instrumental in making this process happen:
public OAuthPage()
{
this.InitializeComponent();
this.Loaded += OAuthPage_Loaded;
OAuthWebBrowser.LoadCompleted += OAuthWebBrowser_LoadCompleted;
}
The OAuthWebBrowser_LoadCompleted event handler enables UI controls when the browser is done loading – notice that the TextBox and Button in the previous XAML have their IsEnabled attributes set to False. When the Page.Loaded event is invoked, the OAuthPage_Loaded handler starts the OAuth process, shown here:
void OAuthPage_Loaded(object sender, RoutedEventArgs e)
{
auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = "",
ConsumerSecret = ""
},
UseCompression = true,
GoToTwitterAuthorization = pageLink =>
Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => OAuthWebBrowser.Navigate(new Uri(pageLink, UriKind.Absolute)))
};
auth.BeginAuthorize(resp =>
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
switch (resp.Status)
{
case TwitterErrorStatus.Success:
break;
case TwitterErrorStatus.RequestProcessingException:
case TwitterErrorStatus.TwitterApiError:
new MessageDialog(resp.Error.ToString(), resp.Message).ShowAsync();
break;
}
}));
}
The PinAuthorizer, auth, a field of this class instantiated in the code above, assigns keys to the Credentials property. These are credentials that come from registering an application with Twitter, explained in the LINQ to Twitter documentation, Securing Your Applications. Notice how I use Dispatcher.RunAsync to marshal the web browser navigation back onto the UI thread. Internally, LINQ to Twitter invokes the lambda expression assigned to GoToTwitterAuthorization when starting the OAuth process. In this case, we want the WebView control to navigate to the Twitter authentication page, which is defined with a default URL in LINQ to Twitter and passed to the GoToTwitterAuthorization lambda as pageLink.
Then you need to start the authorization process by calling BeginAuthorize. This starts the OAuth dance, running asynchronously. LINQ to Twitter invokes the callback assigned to the BeginAuthorize parameter, allowing you to take whatever action you need, based on the Status of the response, resp.
As mentioned earlier, this is where the user performs the authentication process, enters the Pin, and clicks authenticate. The handler for authenticate completes the process and saves the authorizer for subsequent use by the application, as shown below:
void AuthenticatePinButton_Click(object sender, RoutedEventArgs e)
{
auth.CompleteAuthorize(
PinTextBox.Text,
completeResp => Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
switch (completeResp.Status)
{
case TwitterErrorStatus.Success:
SuspensionManager.SessionState["Authorizer"] = auth;
Frame.Navigate(typeof(TweetPage));
break;
case TwitterErrorStatus.RequestProcessingException:
case TwitterErrorStatus.TwitterApiError:
new MessageDialog(completeResp.Error.ToString(), completeResp.Message).ShowAsync();
break;
}
}));
}
The PinAuthorizer CompleteAuthorize method takes two parameters: Pin and callback. The Pin is from what the user entered in the TextBox prior to clicking the Authenticate button that invoked this method. The callback handles the response from completing the OAuth process. The completeResp holds information about the results of the operation, indicated by a Status property of type TwitterErrorStatus. On success, the code assigns auth to SessionState. You might remember SessionState from the previous description of TweetPage – this is where the valid authorizer comes from.
After saving the authorizer, the code navigates the user back to TweetPage, where they can type in a message, click the Tweet button, and observe that they have successfully tweeted.
Summary
You’ve seen how to get started with using LINQ to Twitter in a Metro-style application. The generated code contained a SuspensionManager class with way to manage information across multiple pages via its SessionState property. You also saw how LINQ to Twitter performs authorization in two steps of starting the process and completing the process when the user provides a Pin number. Remember to marshal callback thread back onto the UI – you saw earlier how to use Dispatcher.RunAsync to accomplish this. There were a few steps in the process, but LINQ to Twitter did minimize the amount of code you needed to write to make it happen.
You can download the MetroOAuthDemo.zip sample on the LINQ to Twitter Samples Page.
@JoeMayo