Welcome to MSDN Blogs Sign in | Join | Help

Silverlight [WPF/E] and Windows CardSpace or plugging RIA in the Identity Metasystem

[Edit: Added Silverlight SxS con WPF/E] 

In short: this is a tutorial on invoking Cardspace from a Sliverlight [WPF/E] control and how to use Silverlight [WPF/E] for showing data from a token. So easy that a long haired architect can do it :-)
Silverlight [WPF/E] is Microsoft's technology for developing rich internet applications, but it is also going to be CROSS PLATFORM (the CTP it is already available for Mac). In light of the awesome work of the Bandit guys on an identity selector on other platforms, I believe it is important to start thinking about how to use this new RIA technology together with identity.

 Image claims rendered via WPFE

In recent times I'm hearing more and more people interested in Rich Internet Applications, or RIA. That usually brings the discussion pretty quickly on Silverlight [WPF/E], our cross platform presentation technology that leverages a subset of XAML for doing cool things inside your browser. I am often asked how to plug CardSpace into it, so I thought to put toghether a post that shows how to do that.
As you know it's few years that I am a server guy, so I don't spend too much time on colorful stuff: however I also like to cross pollinate different technologies, and I especially love to do it with CardSpace (I did it with WPF, with WF, with WCF and WPF). Yesterday night I downloaded the WPF/E SDK, the WPF/E runtime for Windows and blocked 1 hour on the calendar of my excellent colleague Laurence Moroney, probably the best mentor I could get for ramping up super fast on this technology. Thank you man!!!!

My objective was to use that hour for coming out with a full Silverlight [WPF/E]+CardSpace PoC, namely: 1) I wanted to invoke the identity selector from a Silverlight [WPF/E] UI 2) I wanted to render some info pulled out from a token. As you can see, there's no buisiness scenario involved: this is pure syntactic sugar, how to get the two to work together. As I hoped, we declared mission accomplished after just 35 minutes :-) below the details.

The steps are

  1. Install the Silverlight [WPF/E] necessaire
  2. Familiarize with the basic Silverlight [WPF/E] project
  3. Modify a cardspace login page for using a Silverlight [WPF/E] control to invoke the Identity Selector
  4. Modify an ASPX page for showing some claims values using Silverlight [WPF/E]

Install the Silverlight [WPF/E] necessaire

If you are new to Silverlight [WPF/E]: you can get all the details here. However, for the purpose of our discussion: Silverlight [WPF/E] is a subset of XAML, the markup language behind WPF, that allows you to deliver in the browser interactive applications containing animation, audio, video, graphic, text and obviously interactivity. The interesting point is that Silverlight [WPF/E] works CROSS PLATFORM, that is to say that your Silverlight [WPF/E] application is available on multiple browsers and multiple platforms (WIndows and Mac). In practice, there will be a lightweight plugin that will enable the browser to understand and render XAML code. Neat!!!
The most recent build is the February CTP. You can get the runtime from here, while the SDK is here. If you use VIsual Studio 2005, after the setup go in the SDK menu folder: there you will find an entry for installing a Visual Studio WPF/E project template, I suggest installing it: it makes things easier for this tutorial.
Note: if you want to nurture your inner designer, Expression Blend is the ideal tool for the task. I am not considering it in this post, since I suspect we are all thick skinned protocol guys around here :-)

 Familiarize with the basic Silverlight [WPF/E] project

In order to avoid wasting Laurence's time, yesterday night I familiarized with the basic Silverlight [WPF/E] project.
If you installed the VS template, go ahead and create a new Silverlight [WPF/E] project. Don't change anything from the defaults. The solution explorer ends up with the following structure:

The file plugin.xaml contains the UI of our control. The syntax is very straightfoward: this is a canvas called button, containing a rectangle and the text "Click Me". There's no binary black magic, this is just plain old human readable XML:

Canvas xmlns="http://schemas.microsoft.com/client/2007"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Loaded="javascript:root_Loaded">

  <Canvas x:Name="button">

    <Rectangle Stroke="#FF8E8E8E" StrokeThickness="2" RadiusX="2" RadiusY="2" Height="23" Width="75">

      <Rectangle.Fill>

        <LinearGradientBrush StartPoint="0.5,2.109" EndPoint="0.5,-1.109">

          <GradientStop x:Name="gradientStop1" Color="#FFFF9E00" Offset="1"/>

          <GradientStop x:Name="gradientStop2" Color="#FFEAEAEA" Offset="0.218"/>

        </LinearGradientBrush>

      </Rectangle.Fill>

    </Rectangle>

    <TextBlock Canvas.Top="3" Canvas.Left="13" FontSize="12" Foreground="#FF5A5A5A" Text="Click Me" />

  </Canvas>

</Canvas>

The file Default.html is the only page of our site. The code is, again, straightforward:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

    <title>Untitled Page</title>

    <script type="text/javascript" src="js/aghost.js"></script>

    <script type="text/javascript" src="js/eventhandlers.js"></script>

</head>

<body>

    <form>

        <div id="wpfeControl1Host" >

            <script type="text/javascript">

                   new agHost("wpfeControl1Host", // hostElementID (HTML element to put WPF/E control into)

                              "wpfeControl1",     // ID of the WPF/E ActiveX control we create

                              "400",              // Width

                              "400",              // Height

                              "white",            // Background color

                              null,               // SourceElement (name of script tag containing xaml)

                              "plugin.xaml",      // Source file

                              "false",            // IsWindowless

                              "30",               // MaxFrameRate

                              null,               // OnError handler (method name -- no quotes)

                            0,                  // Minimum major version required

                            8,                  // Minimum minor version required

                            5                   // Minimum build required   

                             )

            </script>

        </div>

    </form>

</body>

</html>

 

The head contains two references (highlighted in green) to javascript files, the last items files of the solution: we'll see their details shortly.
The body contains a simple form, with a named div and a single call to function agHost. It's not hard to imagine the purpose of the function call: we use it for instantiating in the page our Silverlight [WPF/E] UI. You can notice in the parameters plugin.xaml, the name of the first file we examined in the solution.

We are left with the JS files.
I won't go into the details of aghost.js, nor should you: its function is well explained by the file header, that I am copying below.

///////////////////////////////////////////////////////////////////////////////

//

//  aghost.js

//

//  February 2007 Community Technology Preview

//

//  This file is provided by Microsoft as a helper file for websites that

//  incorporate pre-release WPF/E objects.  The 1.29.2007 version of the file

//  is configured to check for WPF/E version 0.8.5.0.  You may modify this file

//  for testing purposes.

//

//  copyright 2007, Microsoft Corporation

//

///////////////////////////////////////////////////////////////////////////////

The content of the last file, eventhandlers.js, is coherent with its name. It is a collection of javascript functions modeling the behaviors of the Silverlight [WPF/E] control:

function root_Loaded(sender, args) {

    var button = sender.findName("button");

    button.mouseEnter = "javascript:handleMouseEnter";

    button.mouseLeave = "javascript:handleMouseLeave";

    button.mouseLeftButtonUp = "javascript:handleMouseUp";

    button.mouseLeftButtonDown = "javascript:handleMouseDown";

}

 

function handleMouseEnter(sender, eventArgs) {

    var gradientStop1 = sender.findName("gradientStop1");

       var gradientStop2 = sender.findName("gradientStop2");

       gradientStop1.offset = 1;

       gradientStop2.offset = .403;

}

 

...

 

function handleMouseUp(sender, eventArgs) {

       var gradientStop1 = sender.findName("gradientStop1");

       var gradientStop2 = sender.findName("gradientStop2");

       gradientStop1.offset = 1;

       gradientStop2.offset = .403;

      

       alert("clicked");

}

...

 

The function root_loader finds our control, and wires up the events. HandleMouseEnter and other functions (where you see the ellipsis, I have snipped a function away) do some graphic legwork. Again, notice how easy it is to manipulate XAML directly from javascript. What interests us is the line highlighted in yellow: that's the piece of code we want to execute when the user clicks (or better, mouse-ups) the control.

If you hit F5, you'll see a page with a single button that shows an alert when clicked.

 

"Doh", some of you will say. Well, take into account that we didn't change a tad of the template project: I wanted to understand how Silverlight [WPF/E] works, and for that we have to keep the signal/noise ratio to a mangeable value. You are of course invited to make things prettier :-)

Summary. How does a Silverlight [WPF/E] project works? You create your UI in XAML, you instantiate it in an HTML page (via aghost from the aghost.js file) and you handle interactivity via usual javascript events wiring. So easy that a long haired architect can do it.

Modify a Cardspace login page for using a Silverlight [WPF/E] control to invoke the Identity Selector

Now we get to the interesting part. It is all very easy: however, if you are not familiar with the basic CardSpace samples from this point on it will be difficult to follow. I recommend you to download and play with those samples, since you'll have to modify them with what we have just learned about Silverlight [WPF/E]. They are very clear and straighforward, in true Garrett style: from my good friend and book buddy, I would not expect anything less :-)

 Let's get to work. Open your favourite Cardspace sample solution (if you use those samples, I would suggest exercise 3 or 4). What we want to obtain is very easy: we have to elicit the form post from our Silverlight [WPF/E] button instead of the usual HTLM one.
First thing, we copy all the necessaire in the cardspace solution (or in the folder, if you are not using visual studio). The necessaire in this case is the JS directory, with aghost.js and eventhandles, and the XAML file (which for the occasion I renamed LoginControl.xaml).
Once we have copied those, we have to modify the cardspace login page by 1) getting rid of the current mean of POSTing the form (usually a button with type submit) and 2) pasting in the XAML hosting code we have seen above. We will worry about modifying the logic wired to the Silverlight [WPF/E] control in the next steps.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>    <title>Cardspace Login with WPF/e</title>

  <script type="text/javascript" src="js/aghost.js"></script>

  <script type="text/javascript" src="js/eventhandlers.js"></script>

</head>

<body>

    <form id="form1" name="form1" method="post" action="WPFeClaims.aspx">

        <div style="text-align: center">           

            <object type="application/x-informationcard" name="xmlToken">

            <param name="tokenType" value="urn:oasis:names:tc:SAML:1.0:assertion" />

            <param name="issuer" value="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />

            <param name="requiredClaims" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" />           

            </object>

        </div>

        <div id="wpfeControl1Host" >

            <script type="text/javascript">

                   new agHost("wpfeControl1Host", // hostElementID (HTML element to put WPF/E control into)

                              "wpfeControl1",     // ID of the WPF/E ActiveX control we create

                              "400",              // Width

                              "400",              // Height

                              "white",            // Background color

                              null,               // SourceElement (name of script tag containing xaml)

                              "LoginControl.xaml",      // Source file

                              "false",            // IsWindowless

                              "30",               // MaxFrameRate

                              null,               // OnError handler (method name -- no quotes)