Wednesday, December 23, 2009

Strong Naming Assemblies in MSBuild

For a few years, it's been requested our core dll's be strongly named so they can be invoked by 3rd party tools. It's always been a bigger effort (we thought) then the payback so we kept putting it off. Now we need them strongly named so they can be used by say, SSIS.

I spent a ton of time on this just going in circles, and when I actually got it working it was pretty simple. You can strong name your assemblies many ways, but two stand out.
First off, I had problem after problem using the pkcs#12 key I generated using OpenSSL for various tasks (such as signing the manifest for a ClickOnce install, another MS technology). Eventually I read that Microsoft’s strong naming algorithm is just too tight on unnamed standards, and it’s pretty common to get stuck in the endless “Import Key” popup during a manual build, which I did. The fallback is to just generate a key using sn.exe, which I ultimately did.

Using sn.exe to generate a strong naming key is simple, if you’re not concerned about key security. We’re not a shrink-wrapped software place and we have tight controls about the migration of compiled code so I wasn’t concerned about that.

On your build server just do the following out of the bin folder of the appropriate Windows SDK you have installed:

sn -k CompanyBuildKey.snk

and now you have a MS-compliant strong naming key.

The first way to strong name assemblies is to do it in the msbuild script, at compile time.
A good practices is to copy the key to the C:\Program Files\MSBuild folder on the build server, and then you can reference it like this in your msbuild scripts:

$(MSBuildExtensionsPath)\CompanyBuildKey.snk

In your msbuild file on your build server change the following sample line from this:

<MSBuild
Projects="@(ProjectList)"
Properties="Configuration=$(Configuration)"
Targets="Build" />

to this:

<MSBuild
Projects="@(ProjectList)"
Properties="Configuration=$(Configuration);SignAssembly=true;DelaySign=false;AssemblyOriginatorKeyFile=$(MSBuildExtensionsPath)\CompanyBuildKey.snk" Targets="Build" />

This worked fairly well, but it started to generate two worlds – the developers are all unsigned but the build server is signing everything. If a developer wants to use compiled dll’s as references in another project, they can run into issues mixing strong (from the build server) and non-strong dll’s – a strongly named dll cannot call a non-strongly named dll.

So the second method is probably for the best, as it puts everyone on the same page.

Second method:

Move the CompanyBuildKey.snk into a neutral reference. If you have a common library folder in source control that the build server & developers all use, this is a good spot for it.

Move your strong name compiling into each project file and out of the msbuild script.
Add this to each project file:

<AssemblyOriginatorKeyFile>\Common\Folder\For\All\CompanyBuildKey.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>

I hate to put this out without a clean followup, but I can’t do the bulk of the strong naming I need to do for another couple weeks. I’ll try to do a follow-up post on how that works out.

3 comments:

  1. Great post, but the white on yellow is hard to read.

    ReplyDelete
    Replies
    1. Seconded. Had to select the text to read it.

      Delete
    2. I'm 35 and can read it no problem. Woo hoo!

      Delete