Peter McGrattan’s Weblog

Silverlight, WCF, ASP.NET, AJAX, Graphics, RIA

Archive for the ‘ASP.NET’ Category

Silverlight Initialization via the ASP.NET Silverlight Server Control

Posted by petermcg on July 16, 2008

Edited on 20/October/2008 : Code download updated to support Silverlight 2 RTW

(Code download)

This post takes a look at the ASP.NET Silverlight server control and what it renders as markup in response to a web request when added to an ASP.NET page.  It then digs deeper to explore how this markup describes the Silverlight plug-in and how this rendered plug-in is itself initialized in the Microsoft ASP.NET AJAX client framework.  This post also shows how to specify and retrieve Silverlight initialization parameters when using the server control.

The ASP.NET Silverlight Server Control

The Silverlight control is one of two ASP.NET server controls included in the Silverlight 2 Beta 2 SDK; the other is the MediaPlayer control which actually inherits from the Silverlight control.  The control provides an easy way to include Silverlight content in a new or existing ASP.NET Web page using the familiar ASP.NET server control model.  The control is available in the System.Web.Silverlight.dll assembly located under %ProgramFiles%\Microsoft SDKs\Silverlight\v2.0\Libraries\Server in the System.Web.UI.SilverlightControls namespace.  The Silverlight content to be executed by the plug-in this control ultimately renders can be specified by setting the value of the Source property to a URI either to a XAML file or in Silverlight 2 a compiled Silverlight application (a .xap file):

<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/InitParameters.xap"
                 MinimumVersion="2.0.30523" Width="100%" Height="100%" />

The Silverlight server control requires access to a ScriptManager control (generally on the same page) otherwise an InvalidOperationException will be thrown at runtime when the control initializes.

Rendered Markup and the ASP.NET AJAX Client Framework

When rendered to the output stream as part of an ASP.NET page it is declared in, the Silverlight server control delivers four additions to the markup eventually interpreted by the browser.  The first addition the control renders is a JavaScript script block under the html <body> tag with it’s src property set to a path that includes the string "ScriptResource.axd":

<script src="/InitParametersWeb/ScriptResource.axd?d=wMEjThkBoZWGT...;t=633481889860000000"
        type="text/javascript"></script>

This resource is requested by the Silverlight server control in it’s implementation of the IScriptControl interface.  When this script block is encountered as the html page loads a GET request is made to resolve the path assigned to the src property; because the path includes the string "ScriptResource.axd", the request is handled by an instance of the ScriptResourceHandler class as mapped in the default web.config file under the httpHandlers element:

<httpHandlers>
    <add verb="GET,HEAD"
       path="ScriptResource.axd"
       type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0,
             Culture=neutral, PublicKeyToken=31BF3856AD364E35"
       validate="false"/>
</httpHandlers>

The ScriptResourceHandler class implements the IHttpHandler interface in a way that handles request processing for script files that are embedded as resources in an assembly.  In this case the handler eventually resolves the path to a gzip compressed version of either the SilverlightControl.js or SilverlightControl.debug.js JavaScript file (depending on the ScriptMode property of the required ScriptManager control and in turn on the compilation mode in web.config) embedded in the System.Web.Silverlight.dll assembly:

System.Web.Silverlight Resources

It’s the JavaScript code in this file that (amongst other things) registers the Sys.UI.Silverlight ASP.NET AJAX client namespace, the definition of the Sys.UI.Silverlight.Control client component class (with Sys.UI.Control as the base class) and the definition of a method called createObject.

The second addition to the markup is a html <span> element:

<span id="Xaml1_parent"></span>

This <span> element is referenced in the third piece of markup the Silverlight server control renders. Another JavaScript script block, this time with some in-line code that calls the previously defined createObject method:

<script type="text/javascript">

//<![CDATA[

Sys.UI.Silverlight.Control.createObject('Xaml1_parent', '<object 
type="application/x-silverlight-2-b2" data="data:application/x-silverlight-
2-b2," id="Xaml1" style="height:100%;width:100%;">\r\n\t<param
name="MinRuntimeVersion" value="2.0.30523">\r\n\r\n\t</param><a
href="http://go2.microsoft.com/fwlink/?LinkID=114576&amp;v=2.0"><img
src="http://go2.microsoft.com/fwlink/?LinkID=108181" alt="Get Microsoft
Silverlight" style="border-width:0;" /></a>\r\n</object>'
); //]]> </script>

The createObject method takes two parameters here, the first is a string specifying the id of a parent element (the <span>) the second parameter is a string containing html markup for the Silverlight plug-in using the <object> element. The body of the createObject method finds the parent element on the page using the id in the first parameter and sets it’s innerHtml property to be the second parameter. When the innerHTML property is set, the <object> element becomes the content of the <span> element resulting in the object tag describing the Silverlight plug-in becoming part of the browser’s DOM.

The fourth and final markup snippet rendered by the ASP.NET Silverlight server control is the in-line JavaScript script statement shown below:

Sys.Application.add_init(function() {
    $create(Sys.UI.Silverlight.Control, {"source":"ClientBin/InitParameters.xap"},
            null, null, $get("Xaml1_parent"));
});

This script statement adds an anonymous JavaScript function as an event handler for the init event of the Sys.Application client object defined by ASP.NET AJAX. Handlers for this init event are executed after the DHTML window object’s onload event and after the ASP.NET AJAX runtime has been initialized.  The body of this anonymous function contains a single statement that invokes the $create alias defined by the Microsoft ASP.NET AJAX library in the MicrosoftAjax.js or MicrosoftAjax.debug.js JavaScript file embedded in the System.Web.Extensions.dll assembly.

The $create alias is just an convenience for calling the Sys.Component.create function which performs a number of steps.  It creates an instance of the Sys.UI.Silverlight.Control client class within the ASP.NET AJAX client framework as a visual component associated with the span element (this association is required for visual controls) returned as the last parameter from the call to the $get alias. Crucially it sets the value of the ‘source’ property on this component instance to the .xap file using the key/value object literal generated from the server control ‘Source’ property and passed as the second parameter.  It calls the initialize method inherited from the base Sys.UI.Control class on the component instance and finally stores a reference to the instance as a child component of the global Sys.Application object via it’s addComponent method.

At this stage I believe the Silverlight-plug-in, now part of the browser DOM and registered as a visual component in the Microsoft ASP.NET AJAX client framework with it’s source property set to the .xap file, performs the following steps outlined in the Silverlight 2 Beta 2 documentation:

"…starts the common language runtime (CLR) and creates an application domain for the Silverlight application to run in. Downloads the application package, works with the Silverlight runtime to create an execution environment for the Silverlight application, and loads the assemblies and resource files included in the application package. The next step is to instantiate the application class to start the application running."

The Silverlight Application Class

Several of Microsoft’s API’s follow a similar pattern of having an instance of an Application type as the entry point into the program. The client-side ASP.NET AJAX framework, the ASP.NET server-side framework, WPF and Silverlight 2 all employ this pattern. The Application class is the one class that every Silverlight application must implement.  When you create a ‘Silverlight Application’ using the default Visual Studio 2008 template, the Application class is inherited by the ‘App’ class defined in the App.xaml and App.xaml.cs files.  It’s the instance of this App class that initializes and starts the main UI of the Silverlight Application by creating an instance of the Page class (defined in Page.xaml and Page.xaml.cs) and assigning it to the RootVisual property.

Initialization Parameters

To specify initialization parameters to Silverlight from a basic Html page the options are to either set the initParams parameter to a correctly formatted string using JavaScript against the Silverlight plug-in’s object model, or to set the value of a <param> element named InitParams to the same formatted string under the Silverlight plug-in’s <object> tag using Html.  The formatted string should match the pattern : "key1=value1,key2=value2,key3=value3".

The same functionality can be achieved when hosting Silverlight using the ASP.NET Silverlight server control by setting the server-side InitParameters property to the exact same formatted string.  The InitParameters server control property is of type string, is stored in ViewState, and can be set in markup and code-behind; it’s important that this string is in the expected format to ensure the parameters make it to Silverlight.  When a Silverlight server control with it’s InitParameters property set ultimately renders itself, the string is appropriately escaped and passed on to become the value of a <param> element named InitParams inside the generated Silverlight plug-in <object> element.

The key/value pairs in this formatted string are parsed into an IDictionary<string, string> and are able to be retrieved in Silverlight 2 in the StartupEventArgs.InitParams property (e.InitParams) in an event handler for the Application.Startup event:

Application Startup with Parameters

The sample visual studio solution available for download above demonstrates how to specify initialization parameters in both markup and code behind on a Silverlight ASP.NET server control and how to retrieve those parameters in an event handler for the Silverlight Application.Startup event.  The sample also demonstrates passing the parameters on to an instance of the Page class to be displayed in a DataGrid.

Posted in ASP.NET, Silverlight | Tagged: , , , , , , , , | 14 Comments »

Not hitting breakpoints in Silverlight 2.0 Beta 1 project

Posted by petermcg on April 15, 2008

I ran into an issue today when debugging a Silverlight project in Visual Studio 2008.  I had previously been able to hit breakpoints in the project and hadn’t changed any settings, but for some reason it had stopped working.

I knew there was a checkbox in the Property Pages of the hosting web site under Start Options that has to be enabled for breakpoints to be hit when debugging Silverlight Applications, this checkbox is checked by default when you create a new Silverlight Application as shown below:

Default Start Options

Turns out when I checked the properties of my hosting web site project, this checkbox was unchecked – the cause of my breakpoints not being hit, re-enabling solves the problem :

Post-Copy Start Options

But as I said I had previously been able to hit breakpoints in the project and hadn’t changed any settings.  The only thing I had done after closing Visual Studio 2008 last night was to move the solution into another directory under the default Projects folder.

With a bit of investigating it turns out that when I moved the solution to a new folder and then opened the copy in Visual Studio, the Silverlight Debuggers checkbox under Start Options had been cleared.

To re-create firstly create a new Silverlight Application project with the default ‘Web Site’ host and confirm the checkbox is checked under Start Options in the web site’s Property Pages.  Then close Visual Studio and move or copy the whole solution, to the same folder even.  If you made a copy and open the original project the checkbox will still be checked and your breakpoints will work, if you open the copy or the moved solution then the checkbox will have been cleared.

Interestingly the checked value of the Silverlight Debuggers checkbox is not kept for copies with a normal ASP.NET web site when Silverlight is not involved either.  It would be good to find out if this is by design or if I’ve missed something?

Posted in ASP.NET, Debugging, Silverlight | Tagged: , , , | Comments Off

 
Follow

Get every new post delivered to your Inbox.