Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL
Help

10. Talking to REST and WCF Data Service... > Passing credentials and cross-domain...

Passing credentials and cross-domain access to Twitter from a trusted Silverlight application

Passing credentials and cross-domain access to Twitter from a trusted Silverlight application Applies to Silverlight 4 and 5 Whenever we need to communicate with a service that is not hosted in the same domain as the Silverlight application, we need to think of cross-domain restrictions. Silverlight will check if a cross-domain policy file is in place at the root of the domain. Silverlight 4 and 5 applications can not only run out-of-browser (a capability added with Silverlight 3 that allows applications to run as a standalone application, instead of in the browser), they can also run as a Trusted Application. Such an application runs with elevated permissions. On the agreement of the user, the application is installed, and has more permissions on the local system and other capabilities than the in-browser or regular out-of-browser applications. One of these capabilities is accessing cross-domain services without restrictions, meaning that the service will be accessible from Silverlight even if there's no policy file present. Silverlight 4 only supports out-of-browser trusted applications, Silverlight 5 even allows in-browser applications to run with elevated permissions. Also with Silverlight 4 came the ability to send credentials to a service, when using a WebClient instance. The combination of these two added features in Silverlight 4 makes it possible to write a standalone Twitter client that does not need the intermediary service layer, like we used in the previous recipe. Instead, we can now directly communicate with Twitter's API from Silverlight, because there are no cross-domain restrictions. To authorize with the services of Twitter, we need to be able to send credentials, which has also become possible. In this recipe, we'll change the SilverWitter client to run as a trusted, out-of-browser application. Getting ready To follow along with this recipe, you can use your code created with the previous recipe. Alternatively, a starter solution is provided with the samples for the book in the Chapter10/TrustedSilverWitter_Starter folder. The finished solution for this recipe can be found in the Chapter10/TrustedSilverWitter_Completed folder. How to do it... In the previous recipe, we have already built SilverWitter as an in-browser Silverlight application. Due to this, we required a service layer. Silverlight communicates with this service layer, and the service layer in turn communicates with the API of Twitter. If we create the application as a trusted application (that is, with elevated permissions), this service layer becomes obsolete as there are no cross-domain restrictions. We also need to authenticate with Twitter. We'll do so by sending credentials over the service. The following are the steps that we need to follow to create this application: While the UI of the application is similar to the one created for the in-browser version, we need to add a few extra controls. We need to make it possible for the user to install the application. The complete XAML can be found in the code bundle. The following code outlines the changes. We add a StackPanel called InstallPanel, in which the controls for the installation are placed. All other controls are placed in a Grid called MainGrid, for which the Visibility has been set to Collapsed initially. Both the InstallPanel and the MainGrid are now children of the LayoutRoot Grid: <Grid x:Name="LayoutRoot"> <StackPanel x:Name="InstallPanel" Orientation="Vertical" HorizontalAlignment="Center" Margin="10" VerticalAlignment="Top"> <TextBlock x:Name="InstallTextBlock" Text="This application needs to be installed before it can be used. Click the button below to install." Width="500" TextWrapping="Wrap" FontWeight="Bold" FontSize="20"> </TextBlock> <Button x:Name="InstallButton" Click="InstallButton_Click" Content="Install" Width="100" Height="35"> </Button> <TextBlock x:Name="InstallErrorTextBlock" Foreground="Red" > </TextBlock> </StackPanel> <Grid x:Name="MainGrid" Visibility="Collapsed"> <Grid.RowDefinitions> <RowDefinition Height="50"></RowDefinition> <RowDefinition Height="100"></RowDefinition> <RowDefinition Height="*"></RowDefinition> </Grid.RowDefinitions> ... </Grid> </Grid> On starting the application, we need to check if we're running the application inside the browser or as a standalone, trusted application. We can do so using the following code where the Boolean IsRunningOfflineAndElevated contains true if the conditions are met: private bool IsRunningOfflineAndElevated = false; public MainPage() { InitializeComponent(); CheckApplicationState(); } private void CheckApplicationState() { if (Application.Current.IsRunningOutOfBrowser && Application.Current.HasElevatedPermissions) IsRunningOfflineAndElevated = true; else IsRunningOfflineAndElevated = false; } Based on the value of IsRunningOfflineAndElevated, we can change the UI. If it is false, meaning that we're still in the browser, we display the InstallPanel. If it is true, meaning that the application is running as a trusted application, the InstallPanel is hidden and the real application UI is shown. This check is done using the following code, which is called from the constructor as well: private void ChangeUI() { if (IsRunningOfflineAndElevated) { MainGrid.Visibility = System.Windows.Visibility.Visible; InstallPanel.Visibility = System.Windows.Visibility.Collapsed; } else { MainGrid.Visibility = System.Windows.Visibility.Collapsed; InstallPanel.Visibility = System.Windows.Visibility.Visible; } } If the application is not yet installed, we can perform the installation from code. To do so, we can add the following code in the Click event handler of the InstallButton, which will check the current state of the application and install it if needed: private void InstallButton_Click(object sender, RoutedEventArgs e) { if (Application.Current.InstallState == InstallState.NotInstalled) { Application.Current.Install(); } else if (Application.Current.InstallState == InstallState.InstallFailed) { InstallErrorTextBlock.Text = "This application failed to install, please try again"; } else if (Application.Current.InstallState == InstallState.Installed) { InstallErrorTextBlock.Text = "Application is already installed. Please run offline."; } } To store the results coming from Twitter, we need the TweetUpdate class again. However, this class should now be in the Silverlight project. (In the previous recipe, where we had an intermediate service layer, this class was part of the service project.) The code for this class is as follows: public class TweetUpdate { public string Message { get; set; } public string User { get; set; } public string Location { get; set; } } Note Note that the DataContractAttribute as well as the DataMemberAttribute are removed. Both these attributes were needed previously, because instances of this class were used in communication with the intermediate service. We're now ready to start the communication with Twitter. If the IsRunningOfflineAndElevated Boolean variable is true, we can perform a call to Twitter to load the public timeline. This call does not require authentication. Note that we're now writing almost the same code we were writing earlier in the service layer, but now inside the Silverlight application itself. The difference is that now the call to the service happens asynchronously. The following code performs the call to Twitter using a WebClient instance, uses LINQ-To-XML to parse the XML and create a List<TweetUpdates>: public MainPage() { InitializeComponent(); CheckApplicationState(); ChangeUI(); if (IsRunningOfflineAndElevated) GetPublicTimeLine(); } private List<TweetUpdate> publicTimelineTwitterData; private void GetPublicTimeLine() { string publicTimeLine = "http://twitter.com/statuses/public_timeline.xml"; WebClient client = new WebClient(); client.DownloadStringCompleted += new DownloadStringCompletedEventHandler (client_DownloadStringCompleted); client.DownloadStringAsync(new Uri(publicTimeLine, UriKind.Absolute)); } void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { XDocument document = XDocument.Parse(e.Result); publicTimelineTwitterData = (from status in document.Descendants("status") select new TweetUpdate { Message = status.Element("text").Value.Trim(), User = status.Element("user").Element("name").Value.Trim() }).ToList(); PublicTimeLineListBox.ItemsSource = publicTimelineTwitterData; } The application also allows the user to log in. When logged in, the user timeline and friends timeline can be loaded. Both these methods of the Twitter API require that we authorize. Starting with Silverlight 4, we can send credentials when using the WebClient class using its Credentials property. However, sending credentials is only possible when using the ClientHttpStack and not the default BrowserHttpStack. Making Silverlight use the ClientHttpStack is done by using the WebRequest.RegisterPrefix and passing in http://. This code makes sure that all requests over http:// are now executed using the ClientHttpStack. The following code shows the code to retrieve the user timeline (the friends timeline is similar, the code for this can be found in the samples): private void LoginButton_Click(object sender, RoutedEventArgs e) { LoadAuthorizedContent(); } private List<TweetUpdate> userTimelineTwitterData; private void LoadAuthorizedContent() { if (UserNameTextBox.Text != string.Empty && PasswordTextBox.Password != string.Empty) { WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp); string userTimeLine = "http://twitter.com/statuses/user_timeline/" + UserNameTextBox.Text + ".xml"; WebClient client = new WebClient(); client.Credentials = new NetworkCredential( UserNameTextBox.Text, PasswordTextBox.Password); client.UseDefaultCredentials = false; client.DownloadStringCompleted += new DownloadStringCompletedEventHandler (user_DownloadStringCompleted); client.DownloadStringAsync(new Uri(userTimeLine, UriKind.Absolute)); } } void user_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { XDocument document = XDocument.Parse(e.Result); userTimelineTwitterData = (from status in document.Descendants("status") select new TweetUpdate { Message = status.Element("text").Value.Trim(), User = status.Element("user").Element("name").Value.Trim() }).ToList(); UserTimeLineListBox.ItemsSource = userTimelineTwitterData; } To add a message to Twitter from our client, we need to post it using the HTTP POST method. We are using an HttpWebRequest for this, and set its method to POST. To this HttpWebRequest, we also add the user-entered credentials, because this service method requires authorization as well. Silverlight will then send the message to Twitter: private void AddTweetButton_Click(object sender, RoutedEventArgs e) { string uri = @"http://twitter.com/statuses/update.xml"; try { string message = AddTweetTextBox.Text.Trim(); string parameters = string.Format("status={0}&source={1}", HttpUtility.HtmlEncode(message), "Trusted SilverWitter"); WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp); HttpWebRequest request = (HttpWebRequest) WebRequestCreator.ClientHttp.Create (new Uri(uri, UriKind.Absolute)); request.Method = "POST"; request.Credentials = new NetworkCredential(UserNameTextBox.Text, PasswordTextBox.Password); request.ContentType = "application/x-www-form-urlencoded"; request.BeginGetRequestStream(new AsyncCallback(result => { using (StreamWriter writer = new StreamWriter(request.EndGetRequestStream(result))) { writer.Write(parameters); } request.BeginGetResponse(response => { try { WebResponse rs = request.EndGetResponse(response); Dispatcher.BeginInvoke(LoadAuthorizedContent); } catch (WebException ex) { Dispatcher.BeginInvoke(() => HandleError(ex.Message)); } }, request); }), null); } catch (Exception ex) { Dispatcher.BeginInvoke(() => HandleError(ex.Message)); } AddTweetTextBox.Text = string.Empty; } private void HandleError(string exceptionMessage) { ErrorTextBlock.Text = "An error occurred: " + exceptionMessage; } The code is now ready. However, we still need to configure the application to allow it to run out-of-browser and with elevated permissions. To do so, right-click on the Silverlight project node in the Solution Explorer and select Properties. In the Silverlight tab of the Properties window, select the Enable running application out of the browser checkbox. Finally, click on the Out-Of-Browser settings button on the same tab, and in the resulting dialog, select the Require elevated trust when running outside the browser checkbox. With these steps completed, we have created a standalone Twitter client. Because it runs with elevated permissions, there's no need to add an intermediate service layer between the Silverlight client and Twitter. The running application can be seen in the following image: How it works... To build this application, two features added to the platform with the release of Silverlight 4 were put to work: no more cross-domain restrictions when running with elevated permissions and passing credentials using ClientHttp stack. Let's take a look at these in some more detail. Let's go cross-domain! In many recipes in this book, we talked about the cross-domain restrictions that Silverlight has in place. Basically, these come down to Silverlight not allowing us to make requests to services that are not in the same domain as the Silverlight application. Silverlight will make the request only if there's a cross-domain policy file in place that allows the request. Cross-domain restrictions are required for security reasons. We looked at cross-domain issues in depth in Chapter 7,Working with Services. With Silverlight 3, it became possible to create out-of-browser Silverlight applications, allowing us to create standalone Silverlight applications which do not require a browser to be open to run. However, they still run in the sandbox like in-browser applications, meaning these applications do not have extra permissions on the system. With version 4, it becomes possible to create Trusted Silverlight applications, which are basically out-of-browser applications with elevated permissions. As a result, they have more permissions on the system and can perform some tasks in a different manner. One of these is the ability for this type of applications to perform cross-domain calls without the need of a policy file. Silverlight 5 also makes it possible to run trusted applications in-browser. They have the same permissions and added options, so the recipe could be applied on such an application as well. For some applications, this is a big plus. Take, for example, our Twitter application. In the in-browser version, which we created in the previous recipe, we had to build a service layer that sits between the Silverlight client and Twitter itself. The reason for this is that Twitter does not expose a policy file, so Silverlight applications can't directly communicate with Twitter's API. With trusted Silverlight applications, the fact that this file isn't there is no problem. When running with elevated permissions, Silverlight will not check for the existence of the file and will perform the service request anyhow. Applying elevated permissions to Silverlight can be done through Visual Studio. In Project Properties, under the Out-Of-Browser settings, we can check that the application should request to the user to run with these permissions. On installation, the user will not be prompted with the regular install screen. Instead, the following dialog box shown in the following screenshot, asks the user if he or she fully trusts the application: Silverlight also gives us the option to sign the XAP file, which results in a more relaxed installation screen being displayed when installing a trusted Silverlight application. To sign the XAP, you need a certificate. Visual Studio 2010 allows signing the XAP from within the IDE itself. To do so, go to the Project Properties and select the Signing tab (shown as follows) on the left. Here you get the options to use your own certificate, or let Visual Studio create a test certificate for development use. Pass me those credentials, will you? Being able to access Twitter without cross-domain restrictions is one thing. We also need to be able to pass credentials to a service when it requires us to. In Silverlight 3, the WebClient class already had a Credentials property, but this property was not working properly. With Silverlight 4 this changed. It's now possible to pass credentials to a service. One thing that is required is that we use the ClientHttp stack. Passing credentials is very simple and can be done using the following code: WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp); WebClient client = new WebClient(); client.Credentials = new NetworkCredential(UserNameTextBox.Text, PasswordTextBox.Password); We are specifying that we want the application to use the ClientHttp stack using the WebRequest.Register method: basically we're saying for all traffic that goes over http://, use the ClientHttp stack. See also In the Working cross-domain from a trusted application recipe in Chapter 7, Working with Services, we looked at working with trusted applications from Silverlight. Working with Twitter was the topic of the previous recipe.

  

You are currently reading a PREVIEW of this book.

                                                                                                                    

Get instant access to over $1 million worth of books and videos.

  

Start a Free Trial


  
  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint