Building Silverlight 3 and Silverlight 4 applications on a .NET 3.5 build machine
March 20, 2010
Thanks to modular MSBuild tasks and components, you can actually build Silverlight 3 and Silverlight 4 applications on the same build machine, without having .NET 4 installed.
This is great for constrained TFS build environments, and although not supported in any way, this does allow you to edit and build simple Silverlight 4 apps created first for Silverlight 3, using Visual Studio 2008.
Background
On the Silverlight Toolkit team, we have a need to always have a previous version branch, and a new version, building together in a daily TFS Build. We do this by having the Silverlight 3 and Silverlight 4 SDKs, reference assemblies, and other resources checked into the source enlistment.
Caveats
This post is not intended for the general Silverlight developer: it is designed for build engineers and continuous integration fans that need to build both versions. Since the adoption rate of new Silverlight versions is typically very quick, the need to build previous versions diminishes very quickly in my opinion.
Important: this will be using the .NET 3.5 C# compiler, and not the C# 4 compiler. This means that you will not have the ability to build apps that use the new dynamic language feature.
Important note 2: this assumes you are starting with a Silverlight 3 class library or app, not one that you created in Visual Studio 2010. The project file formats in 2010 are updated to use MSBuild 4 and a few other differences, so this scenario (basically building SL3 project formats against the SL4 runtime) is not for everyone.
Important note 3: Visual Studio 2010 supports multi-targeting Silverlight, so you can create projects in 2010 that are 3 or 4 much easier – no need for any of these hacks if your build environment already has .NET 4.
This is based on a previous post about building Silverlight 2 and 3 together.
This method does not require a build machine to have Silverlight installed at all, nor any of its SDKs.
Preparing your source enlistment
You want to copy the various build assets for both Silverlight 3 and Silverlight 4 into the tree, in a folder such as ExternalTools\Silverlight\v3 and v4. Repeat these steps for each version of Silverlight (v3.0, v4.0 directories) you need to build:
- Create a directory to store the MsBuild assets for Silverlight, and copy in the files from %programfiles%MSBuild\Microsoft\Silverlight\v3.0.
- Copy the “Reference Assemblies” directory from %programfiles%\Microsoft SDKs\Silverlight\v3.0\ into the tools directory.
- Copy the “Libraries” directory from %programfiles%\Microsoft SDKs\Silverlight\v3.0\ into the directory.
You can then use relative paths in your projects or custom build targets to get things rolling.
Customizing the <Import /> element in your projects
Within your source enlistment, you must then update all Silverlight project files to instead reference the relative-path building scripts instead of those installed on the machine.
Even when building in Visual Studio 2008, the proper version will build.
On the Toolkit team, all VB and C# source projects within the enlistment reference a relative path, typically something like ..\..\Silverlight.CSharp.targets, instead of the standard Silverlight CSharp targets from the Silverlight MSBuild scripts.
Inside this relative path, it defines the properties. For Silverlight 3:
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <!-- Define the ExternalTools property first --> <SilverlightBuildResources>$(ExternalTools)\Silverlight\v3.0\</SilverlightBuildResources> <TargetFrameworkDirectory>$(SilverlightBuildResources)Reference Assemblies\</TargetFrameworkDirectory> <TargetFrameworkSDKDirectory>$(SilverlightBuildResources)Libraries\Client\</TargetFrameworkSDKDirectory> <SilverlightRuntimeVersion>3.0.40217.0</SilverlightRuntimeVersion> </PropertyGroup> <Import Project="$(SilverlightBuildResources)Microsoft.Silverlight.CSharp.targets"/> </Project>
And for Silverlight 4:
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <!-- Define the ExternalTools property first --> <SilverlightBuildResources>$(ExternalTools)\Silverlight\v4.0\</SilverlightBuildResources> <TargetFrameworkDirectory>$(SilverlightBuildResources)Reference Assemblies\</TargetFrameworkDirectory> <TargetFrameworkSDKDirectory>$(SilverlightBuildResources)Libraries\Client\</TargetFrameworkSDKDirectory> <SilverlightRuntimeVersion>4.0</SilverlightRuntimeVersion> </PropertyGroup> <Import Project="$(SilverlightBuildResources)Microsoft.Silverlight.CSharp.targets"/> </Project>
Note that we are only providing the major version here, this prevents having to update with each new build of Silverlight 4.
Adding Silverlight Toolkit support
To build apps that use the Silverlight Toolkit in a similar manner, just copy the Silverlight Toolkit binaries into the same client libraries folder of the SDK.
WCF RIA Services Note
There’s a hard-coded import statement that will import a single version of the WCF RIA Services if present on the machine.
At the bottom of the Silverlight 4 file Microsoft.Silverlight.Common.targets, you will see this line:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v4.0\Microsoft.Ria.Client.targets" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v4.0\Microsoft.Ria.Client.targets')"/>
You may want to comment out or remove this line if this impacts your multi-version builds in any way.
Hope this helps.