Developing a Silverlight Library Assembly

[This topic is pre-release documentation and is subject to change in future releases. Blank topics are included as placeholders.]

While a single application assembly may be sufficient for some Silverlight applications, Silverlight allows your application to include additional library assemblies. The most common reasons for implementing library assemblies in Silverlight include the following:

  • Enable developers to build reusable, factored units of UI and functionality that are shared across multiple applications.

  • Allow third-party control developers to package, distribute, and sell custom controls.

  • Factor an application’s UI and code by using a combination of in-package and on-demand files. This can improve initial application download and startup times, and overall perceived performance.

This topic shows how to create a library assembly for Silverlight applications, and how to deploy it both in-package and on-demand.

This topic contains the following sections.

Note:

This topic describes development by using MSBuild. For Visual Studio development, see The Silverlight Preview Window.

Just like a Silverlight application assembly, a Silverlight library assembly consists of UI and code. For example, you could implement a UserControl, with both UI and code, in a library assembly as follows:

<UserControl 
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="SilverlightLibrary.Page">

    <StackPanel>
        <TextBlock>Page in a Library Assembly</TextBlock>
    </StackPanel>

</UserControl>


using System.Windows.Controls; // UserControl

namespace SilverlightLibrary
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
        }
    }
}


As with application assemblies, you use MSBuild to generate a library assembly that contains your UI and functionality.

<Project 
  ToolsVersion="3.5" 
  DefaultTargets="Build" 
  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- Library Configuration -->
  <PropertyGroup>

    <ProductVersion>9.0.21022</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <NoStdLib>true</NoStdLib>
    <NoStdCfg>true</NoStdCfg>

    <!--
        Build a library assembly, SilverlightLibrary.dll, with SilverlightLibrary 
        as the root namespace. The generated assembly is placed in 
        the ClientBin folder.
    -->
    <RootNamespace>SilverlightLibrary</RootNamespace>
    <AssemblyName>SilverlightLibrary</AssemblyName>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

    <!-- 
      Specify that this assembly is not a Silverlight application (eg
      does not contain an entry point). The decision on whether
      to deploy this assembly in-package or on-demand will be made by
      the developer later.
    -->
    <OutputType>Library</OutputType>
    <OutputPath>ClientBin</OutputPath>
    <SilverlightApplication>false</SilverlightApplication>

  </PropertyGroup>

  <!-- Silverlight assembly references required by code -->
  <ItemGroup>
    <Reference Include="System.Windows" />
    <Reference Include="mscorlib" />
    <Reference Include="system" />
  </ItemGroup>

  <!-- Code files to build library assembly -->
  <ItemGroup>
    <SilverlightPage Include="Page.xaml">
      <Generator>MSBuild:CompileXaml</Generator>
    </SilverlightPage>
    <Compile Include="Page.xaml.cs">
      <DependentUpon>Page.xaml</DependentUpon>
    </Compile>
  </ItemGroup>

  <!-- 
    The File that is used by MSBuild to Build C# Silverlight Libraries, and
    which specifies the C# compiler. Note that $(MSBuildExtensionsPath) is 
    the path to the Program Files\MSBuild folder.
  -->
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight\v2.0\Microsoft.Silverlight.CSharp.targets" />
</Project>

The key configuration details of this MSBuild project file include the following:

  • The OutputType and OutputPath properties specify to generate a managed library assembly (SilverlightApplication.dll) in the ClientBin folder.

  • References to the three required Silverlight assemblies: Mscorlib (mscorlib.dll), System (System.dll), and System.Windows (System.Windows.dll).

  • References to the code files to build the application class.

  • An Import property that specifies the file (Microsoft.Silverlight.CSharp.targets) which implements the logic for building Silverlight applications.

  • The SilverlightApplication property, set to false, that specifies that this project is built as an application assembly.

Note that an application package should not be generated because this is a library assembly. That is why the XapOutputs and XapFilename properties are not included as they were for an application assembly project (see Developing a Silverlight Application Assembly). A library assembly can be either deployed in-package or on-demand, and the choice is managed by the developer from the application assembly project.

In-Package Deployment for Library Assemblies

Once you have created your library assembly, you have to reference it from your application assembly and configure it for either in-package or on-demand deployment. To configure a library assembly for in-package deployment only requires that you add a reference to the library assembly by using the Reference property in your MSBuild project, as shown in the following:

<Project ... >

  <!-- Application Configuration -->
  <PropertyGroup>
    ...
  </PropertyGroup>
  ...
  <!-- Reference a library assembly for in-package deployment -->
  <ItemGroup>
    <ProjectReference Include="SilverlightLibrary\SilverlightLibrary.proj" />
  </ItemGroup>
  ...
</Project>

This configuration causes the referenced library assembly (SilverlightLibrary) to be embedded in the application package when the application (SilverlightApplication) is built. Consequently, both SilverlightApplication and SilverlightLibrary are downloaded when the application package is downloaded.

The UI and functionality encapsulated by a library assembly can be programmed against by using managed code. For example, the following code shows the App application class from SilverlightApplication. The code sets the Page class in SilverlightLibrary as the application’s main UI by using the RootVisual property.

<Application 
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="SilverlightApplication.App"
    Startup="App_Startup">

</Application>


using System.Windows; // Application
using SilverlightLibrary; // Page

namespace SilverlightApplication
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }

        private void App_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new Page();
        }
    }
}


On-Demand Deployment for Library Assemblies

Deploying library assemblies on-demand can help reduce the application package’s download cost. To specify on-demand deployment of library assemblies you must add MSBuild project configurations and code. First, as for in-package library assembly deployment, you have to configure the application project’s MSBuild project file by adding a reference to the library package. However, this time you also have to specify that the library assembly that is referenced by the application project is not included with the application package when the application assembly is built. You do this with the Private property and set it to false, as shown in the following project file.

<Project ... >

  <!-- Application Configuration -->
  <PropertyGroup>
    ...
  </PropertyGroup>
  ...
  <!-- Reference a library assembly for in-package deployment -->
  <ItemGroup>
    <ProjectReference Include="SilverlightLibrary\SilverlightLibrary.proj">
      <Private>False</Private>
    </ProjectReference>
  </ItemGroup>
  ...
</Project>

The result is that you can now write code that uses types from the library assembly and compile it. As with in-package library assemblies, you can program against the library assembly’s UI and functionality from the application assembly from markup or code-behind. However, without additional work, your application will throw the following exception when it tries to use a class from the library assembly:

ManagedRuntimeError- System.IO.FileNotFoundException: Could not load file or assembly 'SilverlightLibrary, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. An error occurred. at SilverlightApplication.App.App_Startup(Object sender, StartupEventArgs e) at System.Windows.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args) at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)

The FileNotFoundException is correctly raised because the library assembly has not been downloaded.

You must download the library assembly manually before your application can use any classes from the library assembly. The WebClient class provides the functionality to download the class which you then load by using a combination of the Assembly class and the AssemblyPart class. For example, consider a SilverlightApplication with the following UI (HomePage) that allows users to display another UI (Page) from a library assembly that is downloaded on-demand:

<UserControl 
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="SilverlightApplication.HomePage">

    <Grid Background="SandyBrown">
        <StackPanel x:Name="stackPanel">
            <TextBlock>Page from Host Application</TextBlock>
            <TextBlock 
                MouseLeftButtonUp="TextBlock_MouseLeftButtonUp"
                Cursor="Hand">
                Click Here to Display a UI from the Library Assembly
            </TextBlock>
        </StackPanel>
    </Grid>


</UserControl>


using System; // Uri
using System.Net; // WebClient,OpenReadCompletedEventHandler
using System.Windows; // AssemblyPart
using System.Windows.Controls; // UserControl
using System.Windows.Input; // MouseButtonEventArgs

using SilverlightLibrary; // Page

namespace SilverlightApplication
{
    public partial class HomePage : UserControl
    {
        public HomePage()
        {
            InitializeComponent();
        }

        private void TextBlock_MouseLeftButtonUp(
            object sender, MouseButtonEventArgs e)
        {
            // Download assembly "on-demand"
            WebClient wc = new WebClient();
            wc.OpenReadCompleted += 
                new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
            wc.OpenReadAsync(
                new Uri("SilverlightLibrary.xap", UriKind.Relative));
        }

        private void wc_OpenReadCompleted(
            object sender, OpenReadCompletedEventArgs e)
        {
            if ((e.Error == null) && (e.Cancelled == false))
            {
                // Convert the downloaded stream into an assembly that is
                // loaded into current AppDomain
                AssemblyPart assemblyPart = new AssemblyPart();
                assemblyPart.Load(e.Result);

                DisplayPageFromLibraryAssembly();
            }
        }

        private void DisplayPageFromLibraryAssembly() {
            // Instantiate type from assembly
            Page page = new Page();

            // Display it
            this.stackPanel.Children.Add(page);
        }
    }
}


WebClient asynchronously downloads the library assembly (SilverlightLibrary.dll) on-demand from the application’s site of origin. The library assembly is downloaded as a Stream that is converted to an assembly and loaded by AssemblyPart.

Show: