Integrating Silverlight with ASP.NET authentication

It’s the new year so it’s about time I dusted off the Silverlight gloves so I’ve turned my attention back to user authentication with Silverlight. In my ‘bookmarks to look at’ I’d kept Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight which provides a very simple example about how to hook the ASP.NET goodness to Silverlight. One interesting point is that Silverlight uses the same mechanisms as the ASP.NET page so if you login (or logout) with Silverlight then you’ll be logged on (or out) on the ASP site too. It will be interesting to carry on playing with this, I hope to investigate merging this with my Silverlight offline work and roling my own membership provider. Quick point, like me, you’ve not installed SQL Express and are using Vista then change the SQL Local Provider in your Web.Config and not the Machine.Config…trust me you’ll save yourself a lot of frustration.
 

Changing the source of an Image

Sometimes the things you think should be simple can cause you problems in Silverlight. I had a simple Image control on my page and I wanted to change its source depending upon a user selection. So I started with the obvious, myImage.Source = "newImage.jpg" only to be faced with "Cannot implicitly convert type ‘string’ to ‘System.Windows.Media.ImageSource’. Ok fine I’ll create a Uri. myImage.Source = new Uri("newImage", UriKind.Relative) Same problem. Hmm, ok so I’ll go via a Bitmap Image; myImage.Source = new BitmapImage(new Uri("newImage.jpg", UriKind.Relative)) but now I got an error on the page (in the JavaScript error panel). Grr. Well this time it was where the image was that was causing the problem. I’d put the images in a folder on the hosting site that was a peer to ClientBin and used a relative path, so rather than "newImage.jpg" I was actually using "../Images/newImage.jpg". Turns out it doesn’t like that one little bit. Assuming this was a security thing I put the Images folder under the ClientBin folder and that did the trick.
 

Potential help with Silverlight Progressive Enhancement

Just read a blog by Jeff Wilcox about unit testing Silverlight when I spotted a very interesting article about Client-side HTML controls for Silverlight. I’ve you’ve read my blog about using Silverlight as a Progressive Enhancement technology then you know I saw the lack of data typing for Html controls as a problem. However Jefs blog uses a class hierarchy that would seem to solve the issue. So I’ll be downloading the unit testing code to see if it will stream line the inclusion of more Html controls into my sample.

Progressive Enhancement with Silverlight

Progressive Enhancement with Silverlight

I’ve been working with Yahoo’s YUI ajax libraries recently and I’ve been impressed (if frustrated) by their DataTable feature. What I especially liked about it was the idea to combine Progressive Enhancement (i.e. the ability to spruce up HTML by injecting more code and styles via javascript) with re-using the data inside the HTML table. Although I’m sure everyone wants to use nice REST/Web services to fetch their data there is still vast amounts of legacy code out there that is just pumping out HTML tables that have the potential for a good make-over. Now Ajax is fun and all, but for .NET developers Silverlight is the promised land since it uses almost exactly the same skill set. So my theory was, "why can’t I use Silverlight to enhance a HTML table and scrape the data from the HTML rather than a web service?". So that’s exactly what I did, please take look at the picture (I really should get a proper blog) to see what this all looks like. 

The Start, boring HTML table

Here is a boring HTML table, no fancy bits, no resizing, no row selectors, no dragging, no cursor keyboard navigation, etc, etc.

<table>

 <thead> <tr> <th>Surname <th>Forename <th class="bool">Available </th></tr>

 <tbody> <tr> <td>Bassett <td>Berty <td> <tr> <td>Shore <td>Suzanne <td> <td> <input type="checkbox…

Fairly standard stuff, you should note that the table has an Id and the header for ‘available’ has the class ‘bool’, we’ll use those later. I put this Html into the SilverlightTest.aspx page you get when you create a new project.

How to pass arguments into Silverlight?

In order for Silverlight to work its magic over the Html table it first needs to know which table it should be working on, but how? Initially I decorated my classes with ScriptableMember and then registering the class with the browser using;

TableEnhancement tableEnhancement = new TableEnhancement();

HtmlPage.RegisterScriptableObject("SLTableEnhancement", tableEnhancement);

But it started to get muddy since I had to use clunky techniques in order to correctly discover which instance of the user control was running, etc. So I ended up simply passing the table’s id in Silverlights InitParameters (thanks to Mike Taulty for the hint);

<asp:Silverlight ID="Xaml1" runat="server" InitParameters="tableId=MyTable"…
Silverlight gathers that information in the Application, I chose to store it away in a public property;
 private void Application_Startup(object sender, StartupEventArgs e)
        {
            string tableId = e.InitParams["tableId"];
            this.TargetTableId = tableId;
            this.RootVisual = new Page(); 
            …

So now Silverlight knows the id of the element it should target.

How can Silverlight examine Html Elements?

This is quite easy too, Silverlight has access to the Dom;
            HtmlDocument doc = HtmlPage.Document;
       HtmlElement tableElement = doc.GetElementById(tableId);
       …
Although this looks very easy the problem is that HtmlElement is as fine grain as it gets. So I’m grabbing a Html table which has lots of interesting properties and collections whereas HtmlElement boils down to GetProperty, GetAttribute and Children. Ok, so with a bit of to and fro-ing you can get the correct properties but I’d certainly like to see a few helper wrappers here.

How to create/configure the Silverlight DataGrid to represent the HTML table?

As with all grid technologies it’s really easy to get quite an advanced grid by simply binding to a source. But I wanted a little more control of the headers. So I set AutoGenerateColumns="False" and created the headers dynamically, be warned this is early prototype code so I’m making quite a few assumptions about the state of the HTML 😉

                     HtmlElement header = tableElement.GetProperty("tHead") as HtmlElement;
            HtmlElementCollection headerRows = header.Children;
            HtmlElementCollection headerCols = headerRows[0].Children;           
            HtmlElementCollection rows = tableElement.GetProperty("rows") as HtmlElementCollection;
           
            Dictionary<int, DataGridColumn> columnHeader = new Dictionary<int, DataGridColumn>();
            Dictionary<string, object> data = new Dictionary<string, object>();

            HtmlElement trHeader = rows[0];
            for (int i = 0; i < trHeader.Children.Count; i++)           
            {
                HtmlElement td = trHeader.Children[i];
                string headerText = ((string)td.GetProperty("innerText")).Trim();
                string cssClass = td.GetAttribute("className");
                if (cssClass != null && cssClass == "bool")
                {
                    columnHeader.Add(i, new DataGridCheckBoxColumn
                    {
                        Header = headerText,
                        DisplayMemberBinding = new Binding(headerText)
                    });
                }
                else
                {
                    columnHeader.Add(i, new DataGridTextColumn
                    {
                        Header = headerText,
                        DisplayMemberBinding = new Binding(headerText)
                    });
                }               
            }
            …
Ah, now you can see the role of the bool class, when a header is marked as bool I will create a checkbox column. You can probably guess that eventually I will pass that dictionary to the user control with the data grid so I’ll show that;
public override void CreateTable(Dictionary<int,DataGridColumn>headers, IEnumerable dataSource)
        {           
            for(int i=0;i<headers.Count;i++)
            {
                DataGridColumn dataGridColumn = headers[i];               
                this.myDataGrid.Columns.Add(dataGridColumn
                       );
            }
           
            this.myDataGrid.ItemsSource = dataSource;
        }       

How to create a data source from the values in the HTML Table?

As you can see from the previous code snippet the data grid wants an IEnumerable data source. But my data is inside the rather nasty table hierarchy, so how do you create classes on the fly…well good old TypeBuilder that’s how. Now I must confess that I struck lucky here as while I was looking for exactly signature of a data source I happened across http://blog.bodurov.com/How-to-bind-Silverlight-DataGrid-from-IEnumerable-of-IDictionary. I used the sample there to create the classes on the fly, you have to watch that regEx – especially for spaces in your data. I also have to check the memory implications of on the fly creation cause I’ve been bitten by that before. But I’m pleased to say that it worked well.

How to replace the HTML table?

Standard DOM techniques work well for deleting the HTML table, a quick .Parent.RemoveChild worked fine. So everything worked? Well not quite. Silverlight takes a fraction of time to download after the document onload event fires. This means you can see the HTML table before it gets replaced. The simple answer to this is to style it hidden, if the Silverlight loads then it will be removed, if Silverlight doesn’t load then style it back. The problem was knowing if the user has Silverlight or not. The official line is to register the onPlugInError handler which fires when you don’t have Silverlight or just check to see of the Silverlight object is null. Indeed if you disable the Silverlight add-in in IE then it works fine. The problem is with other "unsupported" browsers, such as Opera, Chrome and Windows Safari. Although they don’t run Silverlight they do quite happily load the control. You can right-click and get all the properties of the Silverlight control…however although the light is on no-one is home. Nothing will run, no events will fire but the object is instantiated so the browser cheerfully reports nothing is wrong. It’s a real problem. Fortunately for my example I could simply show the element in the OnLoad and Silverlight will either run and delete it or not run and leave it there. I added a little timer to greatly reduce the opportunity of seeing the HTML version before the Silverlight kicks in;
<script type="text/javascript">
        var timerId;
        function showTable() {
            clearTimeout(timerId);
            var silverlightControl = document.getElementById("Xaml1");

            // if the silverlight control hasn’t been loaded then…
            if (silverlightControl == null) {
                // show the original table
                document.getElementById("MyTable").style.visibility = "visible";
                // hide the download silverlight banner
                document.getElementById("SLHost").style.display = "none";
                return;
            }

            // just cause we’re here doesn’t mean Silverlight is active
            // since other browsers still load the ActiveX face-plate
            var tableElement = document.getElementById("MyTable");
            if (tableElement != null) {
                // I know the Silverligtht control deletes this element,
                // so if it’s still here then show it, if I’m too quick for SL
                // then it will still delete it any second now…
                document.getElementById("MyTable").style.visibility = "visible";
            }
        }

        function useSilverlight() {
            // very quick timer to give everything a chance to settle down and
            // process the message queue          
            timerId = setTimeout("showTable()", 5);           
        }
    </script> 

 

Silverlight performance difference between Mac & PC?

I recently reported how glitchy a Silverlight port of Manic Minor was to play, well today I played the same game on PC (old skool AMD dual core) and a Macbook (Intel Dual Core Duo). Now given the main differences between the two are that the PC has better 3D performance (due to dedicated video card) whereas the Macbook’s processor is usually faster you’d bet that Silverlight, being 3D unaware, would perform better on the MacBook. But no, Manic minor hardly skips on the PC whereas on the MacBook is more like a game of chance than skill. Obviously this isn’t scientific but it does raise the ugly question of the performance of Silverlight on the Mac. Something I’d like to explore once the final release is in the wild.
 

Silverlight User Group – Silverlight, XNA & Gaming

Just got back from the UK Silverlight user group meeting to see ‘Silverlight, XNA & Gaming’ by Pete McGann & Richard Costall. The presentation centred around Pete & Richards conversion of the classic game Manic Minor into .net. Pete, self described ‘bedroom gamer’, gave a very interesting talk about how the game was developed using XNA – a platform/toolset that Pete was very passionate about. Richard then discussed the issues of converting the game from XNA into Silverlight. I found this very interesting, partly cause I too grew up with these games (the reason I started software development) and partly ’cause I’m just about to publish my experiences with developing a game in Silverlight. I was especially interested in the pixel-perfect collision detection, which was probably the last thing I worked on when I was seriously into game development. I certainly hope to have further chats with Pete ’cause I think my old bit mask comparison technique may be faster…maybe 😉  I’m sure that I’ll now include some of the points they raised in this talk into my document but I would like to raise one issue now. The game loop used the storyboard technique (although you can now use a simpler event model in RC0) but chose a value for the interval. IMO, this misses the trick of setting the interval to 0. As Bill Reiss states, ‘If you create a Storyboard with a duration of 0, it will fire its
Completed event one frame after it is begun. So if you begin the
Storyboard again in the Completed event, you’ll have a timer that
executes once per frame’. Now it’s easy for me to say that without really knowing their game but there is a subtle difference between thinking that the storyboard will, "run as fast as possible" to ‘once per frame’. Richard also talked about Pete "slapping his wrists" for not using a time delta in the game loop (more on this in my aforementioned doc) but playing the game on my Mac it too suffers from the same problems I discovered. When you use a delta you effectively store up a number of moves. However, when you do suffer a "glitch" the effect (in this case) is that Minor Willy make sudden random "leaps" which means you end up crashing into the baddies. The game is almost unplayable for me 😦 Perhaps this is the curse of using Silverlight on a Mac??? Is was for a similar reason I removed the delta from Olop. Don’t get me wrong, I think the game is great, but I’d love to get to the bottom of the delta issue.

Overall I enjoyed the presentation and Pete’s enthusiasm for a area of computing that’s dear to me has certainly made me consider dusting off the game programming gloves and possibly even getting hold of XNA too.
Oh Pete (and other retro-gamers) the film you want to watch is King of Kong (a fistful of quarters)

Silverlight release candidate (RC0)

Things are hotting up for Silverlight 2 as Microsoft have release RC0 for download for developers but not for the general public. The idea is that when Silverlight 2 goes live (must be soon, PDC anyone?) then those of us that have developed applications using Beta 2 have a chance to test and fix any breaking changes. I just spent the last 6 hours installing both Visual Studio SP1 and the new Silverlight tools (oh and uninstalling all the previous Silverlight installs). A couple of tips, if you have Blend then uninstall that too, and when you insall VS SP1 it may reboot after installing .net 3.5 Sp1. If that happens then it appears that VS Sp1 has installed (cause VS says so) but in fact in my case it did not. So you may have to re-run the install to complete it (Vista issue?).
 
After installing RC0 you do get a few new goodies, the most obvious of these is a combo box, hurray!!!
 
Happy installing, but prepare to lose your dev machine for a few hours if you’ve not already installed VS Sp1. Here’s waiting for general release Hot
  

Inspired by Remix – a designers view of creating a Silverlight game

After a recent trip to reMix UK my designer friend finally published their process of designing the graphics for a Silverlight game. Have a read, of course this means I’ve got to get my thumb out and write the developers version now!

Silverlight game – Olop

Come play our really difficult (not) Silverlight (you’ll need the latest version) game.

 

Feedback welcome.

 

Controls, left/right cursor keys, space to fire, return to select power up (when lit)

Click to start (or resume when paused)

 

http://www.clearbreezedesign.com/olop.htm

 

I’ll post more about how it was created, the idea was really to try out Silverlight and the processes needed for a developer and a designer to work together. For now just go an help Olop save his Ice Flow 😉

 

Another gotcha using DataContract and Isolated Storage

When my Silverlight application is initialized it loads settings from isolated storage. Everything seemed to be going well when it suddenly started to fail, odd. What is nice is the isolated storage file object has a path property so you can easily navigate through the bizarre set of folder locations and take a look at the actual file. The settings were saved by serializing an object via DataContract and thus ends up as XML. Opening the file I spotted that there was an extra ‘>’ at the end of the file. Suddenly I realised that the problem was the settings were overwriting the data in the file rather than overwriting the whole file. So my last set of settings was one character shorter than the previously persisted set. Changing the isolated file storage settings from OpenAndCreate to just Create solved the problem.