Hello World with Silverlight and Silverlight Streaming
I've been tinkering with Silverlight and Silverlight Streaming and thought I'd share some of my discoveries and pointers.
Silverlight is designed to dovetail into a traditional HTML+JavaScript web app. Your web page loads a Silverlight.js file and constructs a Silverlight object. What happens after that within the Silverlight objects is determined by a XAML ("zammel") file that defines the contents and code references of the Silverlight object.
Silverlight Streaming is a free high-bandwidth hosting service specifically for Silverlight content. Note that it only hosts the Silverlight content of your web app (the XAML files, video content, and .NET managed code assemblies to be downloaded and executed on the client), not your HTML web pages themselves. You'll still need your own web server to serve up your HTML entry page, which can then load up the Silverlight portion of your app from the Silverlight Streaming host.
For a bare bones minimum Silverlight application, you'll need 4 files: An HTML page, a XAML page for Silverlight, a copy of Silverlight.js, and another JavaScript file of your own creation to bind your Silverlight content to your HTML page. You can run all this from localhost once you have Silverlight installed on your machine. For this first run demo, we'll call everything test1: test1.html, test1.xaml, and test1CreateSilverlight.js:
test1.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>A Sample HTML page</title>
<script type="text/javascript" src="Silverlight.js">
</script>
<script type="text/javascript" src="test1CreateSilverlight.js">
</script>
</head>
<body>
<div id="mySilverlightControlHost">
</div>
</body>
<script type="text/javascript">
var parentElement = document.getElementById("mySilverlightControlHost");
createMySilverlightControl();
</script>
</html>
test1.xaml
<Canvas xmlns="schemas.microsoft.com/client/2007"
xmlns:x="schemas.microsoft.com/winfx/2006/xaml">
<Rectangle Width="300" Height="70" Canvas.Left="10" Canvas.Top="10">
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="1,0">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Yellow" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="40" FontFamily="Georgia" FontStyle="Italic"
FontWeight="Bold" Canvas.Top="20" Canvas.Left="20">
<TextBlock.Foreground>
<LinearGradientBrush>
<GradientStop Color="Cyan" Offset="0.0" />
<GradientStop Color="Blue" Offset="1.0" />
</LinearGradientBrush>
</TextBlock.Foreground> Hello World!
</TextBlock>
<!-- Linear gradients -->
<Rectangle Width="140" Height="70" Canvas.Left="10" Canvas.Top="90">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Width="140" Height="70" Canvas.Left="155" Canvas.Top="90">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<!-- Radial gradients -->
<Rectangle Width="140" Height="70" Canvas.Left="10" Canvas.Top="190">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Width="140" Height="70" Canvas.Left="155" Canvas.Top="190">
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="1,0">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Width="140" Height="70" Canvas.Left="300" Canvas.Top="190">
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="1,0">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Yellow" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>
Ok, I got a little carried away with gradient fills. It's fun!
test1CreateSilverlight.js
function createMySilverlightControl()
{
Sys.Silverlight.createObject(
"test1.xaml", // Source property value.
parentElement, // DOM reference to hosting DIV tag.
"mySilverlightControl", // Unique control ID value.
{ // Control properties.
width:'400',
height:'400',
inplaceInstallPrompt:false, // Determines whether to display
// in-place install prompt if
// invalid version detected.
background:'#D6D6D6', // Background color of control.
isWindowless:'false',
framerate:'24',
version:'0.9' // Control version to use.
},
{
onError:null,
onLoad:null
},
null); // Context value -- event handler function name.
}
Put all three files into the root of your local web server (\inetpub\wwwroot for IIS) and copy the Silverlight.js from the SDK or step 1a in the Silverlight Quickstart instructions. Fire up your browser and see what <localhost/test1.html> looks like. If your Silverlight runtime is installed correctly and you've configured your local IIS as instructed, you should see this:
Whee! Pretty colors!
Note: Unlike HTML, entity (tag) names in XAML are case-sensitive. Pay attention to those camel-capped names like TextBlock and RadialGradientBrush. If you've grown accustomed to sloppy casing in your HTML, it's time to start unlearning that.
The good news is that when you get it wrong, Silverlight will tell you what identifier has it confused in a nice error message, instead of just plowing ahead and making the best of an impossible situation as HTML browsers and JavaScript interpreters tend to do.
A Question of Scale
Tinkering with XAML on your localhost web server is very convenient, but eventually you're going to need to think about how to make it real - that is, where you're going to put the stuff so that others can see it. So before we get too far into this Hello World lets take a look at what it would take to push this demo app into a real production environment.
First, we'll need a web server. Seems pretty obvious, and there are many options to choose from. We could set up our own web server on the public (or DMZ) side of our network firewall, or buy into an economy web hosting package from any number of vendors. Twenty bucks a month will get you a fair amount of server storage, SFTP uploads and a modest network traffic quota.
That'll work fine for testing and friends and family use, but what happens if our quirky little app gets "discovered" and linked by a major news feed or gossip network? The app content right now is trivially small, but we're only getting started. If we add rich media such as photos or video content, our cute little app isn't so harmless anymore. Will our home-built server and residential broadband Internet connection be able to handle 1,000 hits per hour? Per minute? If we go the web hosting route, we may survive sudden surges in network traffic, but will we survive the bill that is sure to follow if the surge burns through our traffic quota?
We've hardly finished "Hello World" and we've already reached the classic conundrum of a web startup: Can we afford success?
Silverlight Streaming
Silverlight Streaming offers a solution to that conundrum. You can offload your bandwidth intensive media content from your server to high-bandwidth Silverlight Streaming servers. You still need your own web server and domain name to define the context of the web app, but the heavy lifting can be delegated to the Silverlight Streaming network.
With this solution, you can run a popular web site serving tens of megabytes (even gigabytes) of video content to thousands of visitors per minute on a shoestring server budget. Your web server needs to be able to serve a small html file to thousands of visitors per minute (not difficult, and not likely to blow your traffic quota), and the rest - loading the media content from the Silverlight servers - happens down on the browser client.
So what is involved in hosting a Silverlight app on the Silverlight Streaming service? Not much!
First, you need to provision your Silverlight Streaming publisher account on silverlight.live.com. Login with your LiveID and you'll get back an account ID and an account key. The account ID you'll need later to tell your app where to get the media content from. The account key is for... well, I don't know what it's for. Just keep it safe until we get to the part in this story where an account key is desperately needed. Pretend this is Zork. Keep everything you find, as it almost certainly will be needed later.
Next, we're going to set up the fully locally hosted Silverlight app to run side by side with the Silverlight Streaming hosted content version of the app. Copy test1.html and test1CreateSilverlight.js in your local web server root directory to test1_hosted.html and test1CreateSilverlight_hosted.js in the same directory.
Modify test1_hosted.html in your favorite text editor to replace the script references. Silverlight.js becomes agappdom.net/g/silverlight.js and test1CreateSilverlight.js becomes test1CreateSilverlight_hosted.js. Like this:
test1_hosted.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>A Sample HTML page</title>
<script type="text/javascript" src="agappdom.net/g/silverlight.js">
</script>
<script type="text/javascript" src="test1CreateSilverlight_hosted.js">
</script>
</head>
<body>
<div id="mySilverlightControlHost">
</div>
</body>
<script type="text/javascript">
var parentElement = document.getElementById("mySilverlightControlHost");
createMySilverlightControl();
</script>
</html>
Now modify test1CreateSilverlight_hosted.js to change the Sys.Silverlight.createObject to Sys.Silverlight.createHostedObjectEx and delete all but the source and parentElement object parameters. For the source parameter, change "test1.xaml" to "streaming:/xxxx/test1", where xxxx is your Silverlight Streaming application ID that you got when you created your account in step 1, and test1 is the name of the application slot we're going to create in Silverlight Streaming when we upload this stuff in a moment.
test1CreateSilverlight_hosted.js
function createMySilverlightControl()
{
Sys.Silverlight.createHostedObjectEx(
{ source: "streaming:/xxxx/test1", // xxxx is your app id
parentElement: parentElement // DOM reference to hosting DIV tag.
});
}
So where did all those parameters disappear to? They move to a new file required by the Silverlight Streaming hosting environment called manifest.xml. This file tells Silverlight how to initialize itself. It's always called manifest.xml, and inside it looks like this:
manifest.xml
<SilverlightApp>
<source>test1.xaml</source>
<width>500</width>
<height>300</height>
<inplaceInstallPrompt>false</inplaceInstallPrompt>
<background>#D6D6D6</background>
<framerate>24</framerate>
<version>0.9</version>
<isWindowless>false</isWindowless>
</SilverlightApp>
See? Same data bits as in test1CreateSilverlight.js
Before uploading this app content to the Silverlight Streaming servers, we need to bundle everything up into a zip file. Create a zip file / compressed folder (test1.zip) on your local drive (in your wwwroot directory is fine) and drag manifest.xml and test1.xaml into that test1.zip file. Leave test1_hosted.html and test1CreateSilverlight_hosted.js on your local machine.
Finally, go to silverlight.live.com and click on the "Manage Applications" link on the left. Click on "Upload a Silverlight Application". Enter "test1" as the Application Name (this must match the last part of the streaming: URL in your call to Sys.Silverlight.createHostedObjectEx) and enter the path to your test1.zip file and upload it.
Count to 3 slowly in your head, then fire up <localhost/test1_hosted.html> in your browser. Surprise! It looks just like test1.html. To double check that you're actually running the Silverlight content served from Silverlight Streaming, use View: Source to check that the HTML is referencing agappdom.net/g/silverlight.js and test1CreateSilverlight_hosted.js. If you're still skeptical, shut down your network connection, purge your browser cache and reload the page. If it's being served from your localhost, it will not be affected by the network outage. If the page doesn't load, then that's pretty strong proof that the content is coming from the Silverlight Streaming servers. Congratulations! Now, plug your network back in before you miss something important on the Knight Rider gossip chat room.
Look Ma, No Bandwidth!
You've now got a fully functional rich media application that has a sophisticated, high bandwidth content distribution network running under the hood. The main HTML page and JavaScript glue code are served from your web server, while the potentially bandwidth-heavy rich media content is served from the high bandwidth Silverlight Streaming network.
Oh, and did I mention that Silverlight Streaming is free? Must have slipped my mind. Free streaming and hosting for up to 4GB of server storage. See the FAQ for details.
You can make modifications to the xaml file locally and immediately test with <localhost/test1.html>. When you're ready to upload to "production", copy the xaml file into the test.zip file, then select "Upload Updated Application" on the test1 Application Properties page under Manage Applications on silverlight.live.com and upload your new test1.zip to the server. Upload your test1_hosted.html and test1CreateSilverlight_hosted.js to your production web server, and your app is deployed!
Crawl -> Walk -> Run
The next stage in our Silverlight crawl/walk/run voyage of discovery will be to either drop in some media content such as video or start tinkering with the real black magic inside Silverlight: writing .NET managed code that executes inside the browser, deployed to the client via Silverlight Streaming. I don't have a lot of video sitting around here, but boy, have I got code...
Comments
Anonymous
May 08, 2007
That's all well and good Danny but tell us something interesting. When is Windows Live gonna incoporate Silverlight? :) -JamieAnonymous
May 09, 2007
jamiet: Well, first off, Windows Live is providing the Silverlight Streaming service, so we're already in the thick of it. As for the Windows Live Controls and data APIs, why do you think I'm puttering around in Silverlight? :P The first thing I need to do is figure out an equivalent cross-domain communication technique to use within Silverlight. Thanks for the feedback! -DannyAnonymous
May 09, 2007
Thank you for putting this toghether! This pretty helpful!Anonymous
May 12, 2007
The comment has been removedAnonymous
May 12, 2007
Hi Erik! Long time no see. I don't know offhand if Silverlight can be fired up without a XAML file. I'd suggest digging into the <object> tag generated by the CreateSilverlight call in Silverlight.js to see how construction works on the inside and possibly route around the .xaml assumption. From what I know of <object> tags, the object tag is what creates an instance of the Silverlight object, not the XAML, so it seems like it should be possible to do what you're looking for. I balked at the number of files required for a minimum app, too, but backed off when I found out that one of the reasons for putting the object tag creation in a separate .js file was to avoid "Click to Activate" that most of the browsers now implement. -DannyAnonymous
May 14, 2007
I've been blogging my experiences with streaming services as well at http://timheuer.com/blog/Tags/silverlight%20streaming/default.aspxAnonymous
May 18, 2007
The comment has been removedAnonymous
May 23, 2007
The comment has been removedAnonymous
May 23, 2007
Jocker: Nice catch! "Helpful" software goes a little overboard sometimes in trying to make URLs into links. Fixed. Thanks!Anonymous
May 28, 2007
The comment has been removedAnonymous
May 28, 2007
jawrat: Yes, you can certainly host Silverlight content on your own server infrastructure. Just ignore everything labelled "Silverlight Streaming" and put your XAML and video content up on your own servers! XAML and your managed DLLs can be served by a plain old HTTP web server with the appropriate content-type configurations; the video content probably needs special treatment (Windows Media Server?) rather than an http file server, but I'm making a guess on that one. If I'm way off, holler and I'll go track down something with more truth than guess. Video addressed with http:// is downloaded by Silverlight as progressive video; mms:// is streaming video. Silverlight's video streaming capabilities are not restricted to the Silverlight Streaming service; rather, Silverlight Streaming is an incubation ground for Silverlight rich media apps for developers who don't have the server resources to host rich media for a potentially large audience. If you have your own server infrastructure capable of handling rich media bandwidth demands, please use your own! :P Thanks for the feedback! We should write up an article on this topic (how to build your own Silverlight media server) since this isn't the first time I've heard this question. -DannyAnonymous
May 29, 2007
thanks for the swift reply! ah, but for some reason (probably my own lack of knowledge) changing out http:// with mms:// (the files are there, they work fine in wmp and vlc) doesn't work. silverlight complains about not being able to read the file. perhaps it's not as simple as swapping out the file calls? by the way, i'm playing with both the 1.0 and 1.1 VideoLibrary samples just to see what we can do as that's pretty much what my client wants to do. if you have any ideas, i'm open to suggestions.Anonymous
May 29, 2007
jawrat: Ok, I'll inquire further! Thanks for the feedback. -DannyAnonymous
May 29, 2007
jawrat: Confirmed. Silverlight will play video hosted by your own web server. The video file needs to in .wmv format, and it needs to be encoded using a codec and bitrate that Silverlight supports. Your best bet is to use Expression Media to encode your video content into a Silverlight-compatible .wmv file. Expression will spit out a bunch of files which can just be copied to your web server, including a test page that plays the video. Have fun! -DannyAnonymous
May 30, 2007
okay, so I solved the issue with streaming...apparently, according to http://silverlight.net/forums/t/586.aspx "For streaming, Silverlight only supports http as the streaming protocol, it will not do the actual mms or rstp protocol. In the beta we differentiate between streaming and progressive download by the mms:// vs http:// monikers. This will be addressed for RTM, while we will try progressive and streaming for both, http:// will try progressive first and mms:// will try streaming first, therefore is you keep these monikers as hints to the client, you will get better perf." So, since I had a webserver running on the same machine, I had to use a different port number (8080), and then mms://domain:port/path worked. So, that's one issue resolved. Now, on to the UI and automation. Thanks for your help/hints/advice/info. -JAnonymous
June 15, 2007
Danny Thorpe has a great post on how to get your Silverlight applications working with the SilverlightAnonymous
July 16, 2007
@jawrat do you have a "how to" guide somewhere that shows how you made it work? Thanks!Anonymous
August 14, 2007
Here's a detailed answer to the SECOND good question of the day in today's MSDN event. Windows Live QuantumAnonymous
August 14, 2007
Here's a detailed answer to the SECOND good question of the day in today's MSDN event. WindowsAnonymous
September 26, 2007
The code samples page has been created and is now available. Click here to review what is currently available....Anonymous
October 05, 2007
The code samples page has been created and is now available. Click here to review what is currently available....Anonymous
March 13, 2008
The code samples page has been created and is now available. Click here to review what is currently available....