If you’ve worked with Silverlight you’ve probably used the WebForms control that comes with the Silverlight SDK. Technically, you can still continue to use this control with ASP.NET MVC, you’ll just need to add the ScriptManager with EnablePartialRendering=”false” like so:
<form id="form" runat="server">
<asp:ScriptManager runat="server" EnablePartialRendering="false" />
<asp:Silverlight ID="MySLApp" runat="server"
MinimumVersion="2.0.31005.0"
Source="~/ClientBin/MySLApp.xap"
OnPluginLoaded="pluginLoaded"
InitParameters="myParam=true"
Width="415" Height="280" />
</form>
Sure, this technically still works, but it's not very MVC-like, is it? The new ASP.NET MVC parlance is filled with code snippets and Extension Methods, not Server Controls! We'll instead want something that looks like this:
<%= Html.Silverlight("~/ClientBin/MySLApp.xap", new Size(415, 280),
new {
MinimumVersion="2.0.31005.0",
OnPluginLoaded="pluginLoaded",
InitParameters="myParam=true"
}) %>
Personally, I think the Extension Method way looks a lot cleaner and feels a lot more natural in MVC Land. However, if you don't really see a difference between those two, or see the difference and don't really care one way or another, feel free to continue using the WebForms example and don't bother reading any further. Just be sure to include that ScriptManager, make sure you set EnablePartialRendering="false" and you'll be ready to go.
Creating the Extension Methods
I'm assuming if you're still reading that you not only dig the Html.Silverlight Extension Method above, but you're more interested to see how it works! Well, it's pretty simple, really...
Before I show you the code, let's take a step back and reevaluate what I'm really looking to do here. Sure, I said before that I wanted to replace the Silverlight WebForms control, but what I really want to do is duplicate the HTML it renders (since that's what it's all about, right?). So, here's the markup I'm shooting for:
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" height="280px" width="415px">
<param name='minRuntimeVersion' value='2.0.31005.0' />
<param name='autoUpgrade' value='true' />
<param name='source' value='/ClientBin/LogUploader.xap' />
<param name='OnPluginLoaded' value='pluginLoaded' />
<param name='InitParameters' value='customParam=true' />
<!-- [ Silverlight not installed message here ] -->
</object>
Pretty straighforward, right? Basically, you've got the <object> tag with some pretty standard attributes, then a bunch of <param> tags inside, filled with name/value pairs. Should be pretty simple to reproduce - let's a shot at it. The way I went about it was actually just copying and pasting the above snippet into my C# class and replacing each line with the appropriate C# calls to generate it. Here's what it looks like:
public static string Silverlight(this HtmlHelper html, string relativeControlPath,
Size size, object parameters)
{
var controlPath = VirtualPathUtility.ToAbsolute(relativeControlPath);
var objectTag = new TagBuilder("object")
{
Attributes = {
{"data", "data:application/x-silverlight-2,"},
{"type", "application/x-silverlight-2"},
{"width", size.Width.ToString()},
{"height", size.Height.ToString()},
}
};
var innerHtml = new StringBuilder();
innerHtml.AppendFormat(ParamHtmlFormatString, "minRuntimeVersion", "2.0.31005.0");
innerHtml.AppendFormat(ParamHtmlFormatString, "autoUpgrade", "true");
innerHtml.AppendFormat(ParamHtmlFormatString, "source", controlPath);
foreach (var param in new RouteValueDictionary(parameters))
innerHtml.AppendFormat(ParamHtmlFormatString, param.Key, param.Value);
innerHtml.AppendLine("\n<!-- [ Silverlight not installed message here ] --/>");
objectTag.InnerHtml = innerHtml.ToString();
return objectTag.ToString();
}
There are a couple interesting things going on in this snippet. First off, I start by resolving the absolute path to the Silverlight XAP; this needs to be resolved because this URL will be sent down to the client, and an application-relative path (starting with "~/") does us no good in a browser. Next, I use the new System.Web.Mvc.TagBuilder class which (as Reflector shows us) is what the framework uses to construct HTML in its Extension Methods (such as Html.ActionLink, Html.Form, etc.). I also supply it with a few standard attributes.
![]()
Note that I've hard-coded the Silverlight 2 version info and MIME type... I'm not recommending that you actually do this - it will most certainly attract rabid hamsters to come and eat your code - but for simplicity's sake in doing it in this example anyway.
By this point, you've probably got a pretty good idea about what's going on, but I want to point out one last thing - the usage of System.Web.Routing.RouteValueDictionary. Again taking a cue from the MVC framework itself, I’m using this incredibly helpful (albeit poorly named) class from the new System.Web.Routing namespace to convert anonymous types into a set of key-value pairs that we can then use in our Silverlight method to dynamically add parameters (which are, conveniently enough, simply name/value pairs!).
After it's all done setting everything up, the Silverlight method asks the TagBuilder to render out the markup for our new object tag and its children, and with that, we're pretty much done!