Hosting Silverlight in a SharePoint Webpart

This post will show how to host a Silverlight control in a SharePoint 2007 web part.  This post uses Silverlight Beta 2, I will try to make sure to provide an update after Silverlight RTM's if required.

10/9/2008: [ Update: the VPC image download on mssharepointdeveloper.com has been updated to use Silverlight Beta 2. ]

Background

I have been working with a VPC image from mssharepointdeveloper.com and working through some of the fantastic hands on labs on that site.  One of the labs shows how to host Silverlight in a SharePoint web part.  The problem is that the VPC image that I am working with uses Beta 1 of Silverlight, which has already expired. Update: the VPC image download on mssharepointdeveloper.com has been updated to use Silverlight Beta 2.

In upgrading to Beta 2, it became obvious that this needs to be called out somewhere.

The steps to light up your SharePoint site with Silverlight are:

  1. Install the Silverlight Tools Beta 2 for Visual Studio 2008
  2. Install the Visual Studio Extensions for Windows SharePoint Services (VSeWSS) 1.2
  3. Make sure the Silverlight assembly is in the Global Assembly Cache
  4. Add the Silverlight assembly to the SafeControls configuration section
  5. Configure the MIME type for Silverlight
  6. Add a ClientBin directory for your XAP
  7. Create the Silverlight application
  8. Create your web part
  9. Deploy
  10. Re-read this blog post

Install the Silverlight Tools Beta 2 for Visual Studio 2008

My VPC image (you can download the VPC from here) includes Silverlight Beta 1, which expired.  10/9/2008: [ Update: the VPC image download on mssharepointdeveloper.com has been updated to use Silverlight Beta 2. ] Before installing updated Silverlight 2 bits, you need to do some cleanup.  After uninstalling Silverlight Beta 1 and the Beta 1 tools and SDK, make sure to read this page for information on removing conflicts for the Silverlight Visual Studio tools.

Note: I am going to make a few assumptions about your environment's state at this point, including that you already have SharePoint installed, you have permissions to deploy code to the server and change the configuration files, and that you have Visual Studio 2008 Professional or higher installed.  

The next step is to go to the Silverlight.net site and follow the Getting Started instructions.  This step should be as simple as installing the Silverlight Tools Beta 2 for Visual Studio 2008, which is an add-on to Visual Studio 2008 that makes it easier to develop Silverlight applications.  This will get rid of several of the issues that you are likely to run into, including installing the Silverlight assembly to the GAC.  It will also make it easier to develop your Silverlight application and test it in an HTML page to make sure that works before you work on integrating with SharePoint.

Install the Visual Studio 2008 Extensions for Windows SharePoint Services (VSeWSS) 1.2

The next step is to make sure you are making your life developing for SharePoint as easy as possible by using the Visual Studio 2008 Extensions add-in.  Version 1.2 of VSeWSS supports Visual Studio 2008 and includes a template for quickly building web parts and deploying them, even enabling F5 debugging.  I can't say this enough: if you are developing for WSS or MOSS, you need to use these tools.  The VPC that I am using uses these, and I am going to use this instead of wasting text describing the mechanics of creating a WSP.

Make sure the Silverlight assembly is in the Global Assembly Cache

We ran into this one while doing a short proof of concept for a customer... one of the dev machines did not have the Silverlight assembly installed into the GAC.  This is needed for your SharePoint feature to be able to load the SharePoint assembly and is generally needed for SharePoint development.  You can confirm if it's installed by opening the Visual Studio Command Prompt and entering:

gacutil -l | FINDSTR System.Web.Silverlight

You should be greeted with a response:

System.Web.Silverlight, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL

If so, you are in business.  If not, just locate the assembly and install to the GAC manually.

Add the Silverlight Assembly to the SafeControls Section in web.config

The previous section (putting Silverlight in the GAC) should have been done for you already by the Silverlight installation.  However, it is useful to find the 5-part name of the assembly because we need it in this step.

Open up the web.config file for your Silverlight virtual directory (most likely at C:\Inetpub\wwwroot\wss\VirtualDirectories\80).  In the web.config, you will see a section called "SafeControls" with a bunch of entries.  You are going to add one more entry in that section.

 <SafeControl Assembly="System.Web.Silverlight, Version=2.0.5.0, 
Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
Namespace="System.Web.UI.SilverlightControls" 
TypeName="*" Safe="True" />

Note that you need to REMOVE LINE BREAKS from the above section... that's an attribute value, it just won't all fit on one line and still be visible on my blog.

This entry will enable SharePoint to load the control and safely us it in your applications.

Configure the MIME Type for Silverlight

In order for your application to download the XAP file for your Silverlight application, you need to add the MIME type to your IIS server.  Since my VPC is Windows Server 2003, I'll show how to use it... the steps are pretty much the same in IIS7 and Windows Server 2008, just with a different UI.

Open the properties window for your IIS server:

image

Click the "MIME Types" button.  In the new dialog window, choose "Add" to add a new MIME type.  The extension is ".XAP", and the MIME type is "application/x-silverlight-app".

image

Add a ClientBin directory for your XAP

I have seen posts where people indicate that you put your XAP in a SharePoint list somewhere.  I'd recommend putting the XAP in a ClientBin directory instead, simply because that's how you would manage your SharePoint Features and WSPs.  To do this, go to your virtual directory (typically C:\Inetpub\wwwroot\wss\VirtualDirectories\80) and add a directory, ClientBin.  As a subdirectory, add a folder that will contain the XAP for your application.  For our example, name this subdirectory "HOL".

image

Create the Silverlight Application

This is the really easy part.  Create a Silverlight application in Visual Studio called "HOL.HelloWorld".  When prompted, change the radio button to generate a test HTML page.

image

Visual Studio will create some files for you.  Update the generated Page.xaml:

 <UserControl x:Class="HOL.HelloWorld.Page"
    xmlns="https://schemas.microsoft.com/client/2007"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="100">
    <Grid x:Name="LayoutRoot" Background="White">
        <Canvas Width="400" Height="100" >
            <Canvas.Resources>
                <Storyboard x:Name="FadeIn"> 

                    <DoubleAnimation 
     Storyboard.TargetName="HelloTextBlock"   
     Storyboard.TargetProperty="Opacity" 
     From="0.1" To="1.0" Duration="0:0:2"/> 

                </Storyboard>
                <Storyboard x:Name="FadeOut">
                    <DoubleAnimation 
           Storyboard.TargetName="HelloTextBlock" 
           Storyboard.TargetProperty="Opacity" 
           From="1.0" To="0.1" Duration="0:0:2"/>
                </Storyboard> 

            </Canvas.Resources>
            <Canvas.Background>
                <LinearGradientBrush>
                    <GradientStop Color="Blue" Offset="0" />
                    <GradientStop Color="Red" Offset="1" />
                </LinearGradientBrush>
            </Canvas.Background>
            <TextBlock Opacity="0.1" x:Name="HelloTextBlock" Canvas.Top="30" Width="400" Height="100"
           Text="Hello World!" FontFamily="Trebuchet MS" FontSize="36" 
           Foreground="White" TextAlignment="Center"
           MouseEnter="HelloTextBlock_MouseEnter"
           MouseLeave="HelloTextBlock_MouseLeave"/> 

        </Canvas> 

    </Grid>
</UserControl>

Update the code-behind in Page.xaml.cs:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace HOL.HelloWorld
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
        }

        private void HelloTextBlock_MouseEnter(object sender, MouseEventArgs e)
        {
            Storyboard sb = (Storyboard)FindName("FadeIn");
            if (sb != null)
                sb.Begin();

        }

        private void HelloTextBlock_MouseLeave(object sender, MouseEventArgs e)
        {
            Storyboard sb = (Storyboard)FindName("FadeOut");
            if (sb != null)
                sb.Begin();

        }
    }
}

Hit F5 and make sure your application runs in a browser window.  The next step is to copy the content of the ClientBin directory to the clientbin directory in your virtual directory path.  I simply copied the contents of "C:\SPHOLS\Labs\Lab 05 - Silverlight\01\HOL.HelloWorld\ClientBin" to "C:\Inetpub\wwwroot\wss\VirtualDirectories\80\ClientBin\HOL".  You could alternatively create a post build action that copies the contents of your SharePoint application to this directory.

Create Your SharePoint Web Part

In the same Visual Studio solution, add a new project.  In the Add New Project dialog, choose to create a new SharePoint Web Part project.  I named my project "HelloSilverlight".

image

After your project is created, add a new Web Part called "SLPart".

image

Update the SLPart.cs file to the following:

 using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.SilverlightControls;
using System.ComponentModel;
namespace HelloSilverlight
{
    [Guid("dc79784a-06f0-43da-afa0-0b34f04d5625")]
    public class SLPart : System.Web.UI.WebControls.WebParts.WebPart
    {
        Silverlight silverlightControl = null;

        public SLPart()
        {
        }

        [WebBrowsable(true),
             Personalizable(PersonalizationScope.User),
             WebDescription("Location of the Silverlight XAP package."),
             Category("Silverlight Web Part"),
             WebDisplayName("XAP Source Location")]
        public string Source { get; set; }

        [WebBrowsable(true),
             Personalizable(PersonalizationScope.User),
             WebDescription("ID for the Silverlight control."),
             Category("Silverlight Web Part"),
             WebDisplayName("Silverlight Control ID")]
        public string SilverlightControlID { get; set; }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);
            if (scriptManager == null)
            {
                scriptManager = new ScriptManager();
                this.Controls.AddAt(0, scriptManager);
            }

        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            silverlightControl = new Silverlight();
            //silverlightControl.ID = "HelloSilverlight";
            silverlightControl.ID = SilverlightControlID;
            //silverlightControl.Source = "/ClientBin/HOL/HOL.HelloWorld.xap";
            silverlightControl.Source = Source;
            silverlightControl.Width = new System.Web.UI.WebControls.Unit(400);
            silverlightControl.Height = new System.Web.UI.WebControls.Unit(100);
            //silverlightControl.MinimumVersion = "2.0";
            Controls.Add(silverlightControl);
        }

    }
}

What this code does is to add a ScriptManager to the page if one doesn't already exist.  It also adds a Silverlight control to the Controls collection, pointing to the ClientBin directory I discussed previously.  To point to the ClientBin, you will need to configure the web part once it is deployed.  The cool thing about this (thanks to Tim Heuer for the suggestion) is that it can be used with any XAP... this can be used as a generic XAP web part.

Deploy Your Web Part

This is where the beauty of using VSeWSS 1.2 comes in... it automatically will create a WSP for you, deploy it, install it, deploy your assembly to the GAC, and register your assembly in the SafeControls section in web.config.  Deploying your web part is really simple... just set your web part project as the startup project in Visual Studio 2008, set a breakpoint in the SLPart class, and hit F5.  Visual Studio will do the rest for you, including enabling you to use step-through debugging.

Once the web part is deployed, modify the shared settings for the web part to specify the control ID and the XAP location.  I specified the Source as "/ClientBin/HOL/HOL.HelloWorld.xap" and the Control ID as "HelloSilverlight".

image

Re-Read This Blog Post

It looks like there's a lot of work here, but there's really not that much... most of the work made sure your environment has the necessary developer tools.  Once you get that stuff out of the way, your real challenges are to make sure that your Silverlight application is deployed to the proper ClientBin directory and that your Silverlight server-side control knows where to find it.

I highly suggest that you visit MSSharePointDeveloper.com and watch the webcasts, download the VPC, and work with the Hands On Labs.  These are a fantastic resource for learning how to get started as a SharePoint developer.