Build the Assembly & Third Party Dependencies Cerberus’s Second Head
We now have our Strong-Named Assembly from Part 3 and all we have to do is compile and install it to the Server’s GAC…or so you thought. About the time I ran MSBuild I remembered Cerberus’ is a multi-headed demon dog and the second head now had a smirkish grin, my third party assemblies were not signed and therefore not strongly named. The specific error was;
"Referenced assembly 'MongoDB.Bson' does not have a strong name"
Remember that series of upgrades I mentioned in Part 2? One of the changes was upgrading from version 1.8.2 to 1.10.0 of the official Mongo CSharp Driver. The issue with that was Mongo in their infinite wisdom decided they would stop strong signing their assemblies with version…you guessed it, 1.10.0. This should have been an easy roll-back, except the rest of the solution had already been converted and was using the 1.10.0 driver. The FTP Authentication DLL had actually been broken ever since that upgrade, however it is not a part of the standard build and release process so the old DLL was never overwritten. By absolute luck the old driver was still working for this DLL, although it should not have, which is why we never noticed until now.
Now that the initial blow from Cerberus’ has knocked me on my rear I had to get back up and make a decision. Option one I could clone the MongoCSharpDriver repository on GitHub and strongly name the assemblies myself or Option two, figure out how to give a strong name to the precompiled assemblies I installed from a nuget package. I did Fork the driver repo and tried to build a strong named assembly myself but that opened up a whole new bag of snakes, about 300 snakes in the form of compiler errors. I had seen some articles about strongly naming third party assemblies so I decided to try that route instead. After all I was already battling Cerberus I didn’t want to take on Medusa as well (See what I did there?). Fortunately Microsoft isn’t all bad and their .NET Framework SDK has some handy tools to help with the fight.
Tools Provided by Microsoft
ilasm.exe – Intermediate Language Assembler
ildasm.exe – Intermediate Language Disassembler
gacutil.exe – Utility for managing the GAC
sn.exe – Strong Name tool for signing and managing an assembly’s strong name.
Signing the Third Party Dll’s
Read this .NET-fu article if you want the really detailed explanation and reasoning behind doing this. I found the second scenario covered to be extremely helpful because 2 of the 3 assemblies I was signing referenced the third which required a little more black magic. I left in the Mongo Assembly names so you can follow how the signing hack works for pre-compiled assemblies. Here are the steps I took.
ildasm /all /out=MongoDB.il MongoDB.Bson.dll ildasm /all /out=MongoDB.Driver.il MongoDB.Driver.dll ildasm /all /out=MongoDB.Driver.Core.il MongoDB.Driver.Core.dll
Disassmebling the DLLs creates 2 files, an intermediate language file *.il and resource file *.res. The *.il file is what we are interested as it contains a list of external assembly references.
5.) Reassemble the DLL and sign with the same keyfile we are using for our assembly
ilasm /dll /key=MyKeyfile.snk MongoDB.Bson.il ilasm /dll /key=MyKeyfile.snk MongoDB.Driver.il ilasm /dll /key=MyKeyfile.snk MongoDB.Driver.Core.il
6.) All that was left was for me to Open the project in Visual Studio remove the old references and add new ones to the strongly signed DLLs. At this point when you compile the you may get the following error.
“Could not load file or assembly ‘MongoDB.Bson Version=2.0.1, Culture=neutral publicKeyToken=none, architectureType=MSIL”
But wait… that assembly were just signed why does it say PublicKeyToken=none! Well that’s because in this case MongoDB.Driver and MongoDB.Driver.Core reference MongoDB.Bson and the first go around signing the assemblies we did not update that reference. Fortunately with the same tools I could inject the Public Key token into the reference to MongoDB.Bson Start by disassembling the DLLs that are also dependent on one of the third party DLLs. You’ll know which ones because the error in Visual Studio will tell you.
ildasm /all /out=MongoDB.il MongoDB.Bson.dll ildasm /all /out=MongoDB.Driver.il MongoDB.Bson.Driver.dll ildasm /all /out=MongoDB.Driver.Core.il MongoDB.Driver.Core.dll
Now that I have my *.il and *.res files back I needed the Public Key Token from the signed MongoDB.Bson.dll. Yet again the SDK has a tool for that.
sn -Tp MongoDB.Bson.dll
5.) The above command prints out the HEX version of public key token. I took that token and copied it into each of the *.il file produced by the last ildasm calls. All I had to do was open the *.il file in my favourite(Yes! I use the English spelling) text editor, search for “.assembly extern” and insert the following key underneath the block of text that starts with MongoDB.Bson. Again this is done for each of the *.il files. I’ll give 5 pts to the first person that can guess what my Public Key says.
.assembly extern /*23000002*/ MongoDB.Bson
.publickeytoken = (C0 FF EE 70 AD 57 00 15)
6.) Now that these *.il files reference the strongly named MongoDB.Bson dll they can be reassembled.
ilasm /dll /key=DataX.FTPAuthProviderKey2.0.snk MongoDB.Bson.il ilasm /dll /key=DataX.FTPAuthProviderKey2.0.snk MongoDB.Driver.il ilasm /dll /key=DataX.FTPAuthProviderKey2.0.snk MongoDB.Driver.Core.il
7.) Open Visual Studio and remove the references to the old DLL’s and add references to the newly signed DLLs.
8.) This time when you compile you’ll also be forcing Cerberus’ second head into submission, because you shouldn’t be getting anymore errors and that is a fantastic feeling.
One last head to go and then the long trek back out.