共用方式為


Windows 7 slate PCs Part 2

Last time, I gave some motivation and context for this series and discussed a couple of topics.  This time, we will look at identifying the user (Authentication) using  OAuth and calling web services using HttpWebRequest.

NB: Code presented here is of example quality only. Please don’t cut and paste this code into your solution. Proper error handling, logging and graceful failures are not included.

Note on Dynamic

Many of the examples I will show use the dynamic keyword.  You can use the dynamic keyword in a SLOOB. In order to do this, reference the Microsoft.CSharp assembly. This is very helpful for COM Interop.

OAuth

If you’re not familiar with OAuth, it is a secure, open protocol to perform Authentication (user identification).  Popular services like Facebook and Twitter use OAuth to authenticate users.  If you’re planning on using one of these services in your application (and let’s face it, you should be), you will need to use OAuth.

There are two methodologies for doing OAuth from a SLOOB.  Both involve the server-side.  Cross-domain calls from a SLOOB are verboten.  You have to use the server-side.  Methodology #1 is a web services approach.  Your client calls back to a service you provide.  The OAuth process looks like this:

1. The SLOOB sends a request to the OAuth provider (Twitter, Facebook, whatever).  The response is an auth token that is used to generate a URL.
2. The client displays the contents of the URL to the user wherein the user is prompted to provide credentials.
3. The OAuth provider gives the user a code.
4. The user provides the code to the SLOOB.
5. The SLOOB calls the OAuth provider informing it that it needs an access token and provides the auth token from step #1.  The SLOOB passes the
    auth token and the code from step #3 to the OAuth Provider.
6. The OAuth provider returns an access token used to access the service.

In order to accomplish this process, you need to sign your application with the OAuth provider (here’s Twitter’s page for example).  You will get an app id that you need to provide to the OAuth provider during your request back and forth.

There is some good source code you can check out for OAuth on the Fabrikam Shipping SaaS demo.

There is another approach you can take that is a little easier.  This approach involves an embedded web browser control is hosted by the SLOOB is used to display an authentication web page. (Bringing up a separate browser for this purpose is less effective and a worse experience for your user). If the user provides correct credentials, she will be redirected to a page provided by the SLOOB to the OAuth provider – a successful login page. The login success page is created, hosted and maintained by you, the SLOOB publisher. This will be a simple page that will use ECMAScript to notify the SLOOB of the auth token granted by the service. For example, assuming the token (or the secret needed to get the token) is in the URL, success.htm might look like this:

 <html>
  <head>
    <title>OAuth Login Callback</title>
    <script type="text/javascript">
      window.external.notify(window.location.href);
    </script>
  </head>
  <body />
</html>

Gotcha: This page must originate from the same domain as the SLOOB (also called the “site of origin”). If the user installed the application from the foo.org domain (or provided the foo.org with the /origin switch for a command line install), the page with the ECMAScript must be hosted on the foo.org domain. If it is not, a cross-site scripting exception will be thrown by Silverlight.  This page should be accessed using transport level security (SSL).

Gotcha: If the SLOOB that wants to do OAuth is installed from the command line, the /origin switch must be used to indicate a site of origin.

Once this page is visited, a ScriptNotify event will be raised and can be caught by the SLOOB.  The SLOOB can extract the access token from the arguments passed to ScriptNotify.  Check out this article describing that process and a good description of some pitfalls.

HttpWebRequest v.s. WebClient (Dev)

When accessing RESTful back-end services from a SLOOB, there are a couple of choices you can make as to how you will code the access.  You can use the WebClient class or you can use the HttpWebRequest.  In general, the WebClient is easier to code against and offers more built-in functionality than the HttpWebRequest.  But, there is one very significant difference that often goes overlooked.

The WebClient class returns its data on the UI thread whereas HttpWebRequest does not!

You will get better UI performance for multiple or long downloads if you use HttpWebRequest.

Gotcha: (code from a sample SLOOB showing the requirement for marshaling)

 private void button1_Click(object sender, RoutedEventArgs e)
{
    var cli = new WebClient();
    cli.DownloadStringCompleted += (s,dceh) => { UpdateUI(); };
    cli.DownloadStringAsync(new Uri(@"https://www.bing.com/", UriKind.Absolute));
}
 
private void button2_Click(object sender, RoutedEventArgs e)
{
    var cli = HttpWebRequest.Create(new Uri(@"https://www.bing.com/", UriKind.Absolute)) as HttpWebRequest;
    cli.BeginGetResponse( ia => UpdateUI(), null);
}
 
private void UpdateUI()
{
    if (textBlock1.CheckAccess())
    {
        textBlock1.Text = "no marshal";
    }
    else
    {
        this.Dispatcher.BeginInvoke(() => { textBlock1.Text = "marshal"; });
    }
}

If you’re wondering why WebClient is blocking your UI, the answer is that it’s designed to do that to spare you the “trouble” of cross thread marshaling.  On the flip side …

Gotcha: It is more difficult to give determinant upload progress to your user when using the HttpWebRequest class.  These events are built into the WebClient, but not into the HttpWebRequest.

Next time, we will look at some more esoteric (but no less important) topics and we will do some WMI! Smile