September 2008 - Posts - Jon Galloway

September 2008 - Posts

Running Silverlight 2 on Google Chrome using the Chrome Dev Channel

When Google Chrome first came out and I read that it used Webkit, the same rendering engine that powers Safari, I tried browsing a few Silverlight 2 sites. It kind of worked, as long as the sites didn’t exclude browsers that weren’t on Microsoft’s official Silverlight support list. The controls loaded, but didn’t animate or update smoothly. While Microsoft still isn’t officially supporting Silverlight on Chrome, Chrome’s latest Dev Build (0.2.151.2) includes some specific fixes to support Silverlight 2 Beta 2. The information about the updates is in the release notes, specifically revision 1735:

The basic issue here was that the plugin would not paint correctly. The URLs mentioned in this bug load windowed silverlight plugin instances, which invoke the NPN_InvalidateRect API to paint. We send over the rects to the renderer, however these don't generate paints as the plugin is windowed. A peek at Safari's webkit implementation revealed that they merely invoke the InvalidateRect windows API in this context.

I followed the link in Jonas Follesø’s post over to the Chromium Developer instructions for running the Chrome developer build, which are really simple:

  1. Download and run the Google Chrome Channel Chooser (http://chromium.googlecode.com/files/chromechannel-1.0.exe).
  2. Click the circle next to Dev.
  3. Click Update to save your choice.
  4. Click Close.
  5. In Google Chrome, click the wrench menu and choose About Google Chrome. Note: On Windows Vista, updates from the About box require Service Pack 1. With 0.2.149.29 (the current release), on demand updates do not work in Vista SP1 if User Account Control is disabled.
  6. Click Update Now to install the current Dev channel release.
  7. Restart Google Chrome.

And yes, it really is that easy – I had it running in under 5 minutes. First, I ran the Chrome Channel Switcher. It’s a simple EXE, not an install. Select Dev, press the Update button, then press the Close button:

Google Chrome - Build Channel Switcher

Then open the about box (in the wrench menu) and click the Update Now button:

Google Chrome / About Menu

Google Chrome - Dev Build Update

The update runs:

Google Chrome - Updating

After the update finishes, close and reopen Chrome. If you want to verify you’ve updated, check the about box – you’ll see the version number is different:

Google Chrome 0.2.152.1

That’s it. The whole process took just a few minutes for me. Now, off to view some of my favorite Silverlight 2 Sites! First, the Hard Rock Memorabilia page. There’s a check to see if the browser is supported, but it still lets me in if it’s not on the list (which is a good policy anyways, since it allows Linux / Moonlight users to view the site):

Google Chrome / Silverlight / Hard Rock Memorabilia

I hit okay, and we’re in. The site is snappy and everything works just fine:

Google Chrome / Silverlight / Hard Rock

How about the Mojave Experiment site, which uses a fancy Deep Zoom / video cloud thing? Yep.

Google Chrome / Silverlight / Mojave Experiment

Jonas has some screenshots of other Silverlight sites, which also worked well for him, and it worked for Samiq as well. From the release notes, this Dev release also fixes issues with Flash, such as YouTube videos freezing when you use the slider. Go get it!

Note: All the computers I tested this on had Silverlight installed before upgrading Google Chrome to the dev build. One had Safari / Windows installed, the other didn’t. Google Chrome doesn’t include Silverlight; you’ll need to install Silverlight separately if you don’t already have it.

Silverlight and Relative URI’s for Image and Video Sources

One of the main use cases of Silverlight is to enable rich media experiences, which requires referencing media files (images, audio, and video). That’s a little trickier than you’d expect, and it’s not very clearly documented. For instance, we ran into difficulty getting this set up in our Silverlight Advertising demo for MIX – we wanted to allow for a drag and drop experience to add a video as a canvas background without requiring additional downloading code to pull the video. Here’s an overview on how that works (thanks to Tim Heuer and for much of this information).

NOTE: This is especially important if you’re including a video or lots of images. The wrong way to include large media assets is to include them as resources (either compiled into the DLL or included in the XAP), since that will require your users to download everything before the Silverlight control is displayed. It’s important to keep your Silverlight XAP’s small so your users have a smooth load experience. For instance, the Hard Rock Memorabilia site browses gigabytes of images, but the XAP size weighs in at a tiny 69KB.

Silverlight URI References Are Relative To Your XAP

Short story is, Silverlight media Uri references don’t work the way you’d think, largely to keep compatible with WPF Uri’s which aren’t living inside a website. Relative Uri’s are relative to the Silverlight application, not the website. There’s no way to do site relative Uri’s without writing code. For example, using the following site structure:

Silverlight - Relative URI

Note: Screenshot has been updated since original post.

In this case, a source Uri could reference VideoB.wmv, but couldn’t reference VideoA.wmv or any images in /Images. So these are valid:

<MediaElement Source="/VideoB.wmv" />
<MediaElement Source="Subfolder/VideoC.wmv" />

These are not:

<Image Source="/Images/Logo.png" />
<MediaElement Source="/VideoA.wmv" />

Some Workarounds

  1. Include the content in a subfolder of ClientBin. Set the content type to “Content” rather than “Resource” unless you want it downloaded with the XAP. Don’t include the media as a resource, or your users will have to download all the video and images before the Silverlight element is displayed.
  2. You can manually move the XAP in the root of the site, and site relative paths will work. This solves the Uri issue, but then you’re on your own a bit because you’ve stepped outside of what Visual Studio’s tooling supports. Shawn Wildermuth recommends moving your XAP to the root of an application and has a good post on how to do it.

Pete Brown wrote a nice overview explaining how relative URI’s work in the three possible cases:

Images with Leading Slash (like <Image Source="/foo.jpg" />)

This type of references, with a leading slash, is root relative to the application root (the XAP). These files should by Content and have CopyToOutputDirectory set so that they are added into the XAP. If you inspect the Xap, you'll find the image in there.

When not found, the resource loading mechanism falls back to the application's site of origin and looks for the image under the same dir as the XAP is located. Note that this is the application's site, not the hosting page's site. That is an important distinction if you are creating cross-domain applications (where Site X has the page and Site Y has the XAP). If not found, an exception is thrown.

Images without Leading Slash (like <Image Source="foo.jpg" /> )

This type of reference, without any leading slash or anything, expect to find the image compiled into the assembly as a Resource. The path is relative to the path of the Xaml file from which they are being referenced. When not found, the ImageFailed event is raised

If you inspect the XAP, you will not see the image, because it will be in the assembly.

Absolute URLs (like <Image Source="absolute http url" />)

This will look at the named absolute Url as you would expect.

The absolute URL sounds like the simplest approach, and it is – from the Silverlight point of view. It’s not the simplest for web development, though, because your references won’t stay the same between your development, test, and production machines. In general, I use the leading slash references with the media files hosted at the “site of origin”, meaning the site at which the XAP file is hosted.

One More Gotcha / Workaround – WebClient and HttpWebRequest Don’t Follow The Above Rules

WebClient and HttpWebRequest use the browser’s network stack, so they work the way you’d expect for normal web applications. For example, in the following code:

var webClient = new System.Net.WebClient();
webClient.OpenReadCompleted += ProcessResult();
webClient.OpenReadAsync(new Uri("/info.zip"));

The web client request is routed through the browser’s networking stack, so it would be looking for info.zip regardless of where your XAP file is located in your site. I guess the downside there is that your location context changes depending on how you’re accessing resources (via Uri reference or by explicitly connecting to it via WebClient/HttpWebRequest). However, there’s an upside – your XAP can reference content anywhere in your site via WebClient/HttpWebRequest, even if the XAP is located in a subfolder. That’s handy, because in some cases that can be a lot simpler than determining the absolute URL of your resource.

Posted by Jon Galloway | 5 comment(s)
Filed under:
More Posts