SYSK 361: On the importance of signing assemblies from the versioning perspective

There are many reasons for signing your assemblies (security being at the top of my list), but in this post I’d like to address the importance of using a key to sign your assemblies from the versioning point of view.

 

Now, let’s assume for the sake of this discussion, that we’re talking about private assemblies (no GAC). So, let’s consider a simple factory pattern: client calls a factory class to get an object, the factory uses the context and configuration information to determine the right implementation, creates an instance of that object and returns it to the caller.

 

For simplicity sake, let’s say you deploy the different implementations of a class in versioned folders, but keep the assembly name, e.g.

…\bin\Client.exe

…\bin\ClassLibrary\v1.0.0.0\ClassLibrary.dll

…\bin\ClassLibrary\v2.0.0.0\ClassLibrary.dll

 

Once the factory class resolves which class implementation it needs to instantiate, it can use different mechanisms to actually create the object, e.g.:

Assembly asm = Assembly.LoadFrom(@"ClassLibrary\v1.0.0.0\ClassLibrary.dll");

ClassLibraryInterfaces.IClass1 class1 = asm.CreateInstance("ClassLibrary.Class1") as ClassLibraryInterfaces.IClass1;

 

or

 

ClassLibraryInterfaces.IClass1 class1 = AppDomain.CurrentDomain.CreateInstanceAndUnwrap(@"ClassLibrary, Version=1.0.0.0, publicKeyToken=1db56723ca128f1b, culture=neutral", "ClassLibrary.Class1") as ClassLibraryInterfaces.IClass1;

 

or

 

Assembly asm = Assembly.Load(@"ClassLibrary, Version=1.0.0.0, publicKeyToken=1db56723ca128f1b, culture=neutral");

ClassLibraryInterfaces.IClass1 class1 = asm.CreateInstance("ClassLibrary.Class1") as ClassLibraryInterfaces.IClass1;

 

Of course, you would need to give a hint to the runtime about where to find your assembly either via the probing element or codebase:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <runtime>

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

      <probing privatePath="ClassLibrary\v1.0.0.0;ClassLibrary\v2.0.0.0"/>

         </assemblyBinding>

  </runtime>

</configuration>

or

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <runtime>

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

     <dependentAssembly>

        <assemblyIdentity name="ClassLibrary" publicKeyToken="1db56723ca128f1b" culture="neutral" />

        <codeBase version="2.0.0.0" href="ClassLibrary/v2.0.0.0/ClassLibrary.dll" />

        <codeBase version="1.0.0.0" href="ClassLibrary/v1.0.0.0/ClassLibrary.dll" />

      </dependentAssembly>

         </assemblyBinding>

  </runtime>

</configuration>

 

However, if you don’t sign your assembly with a key (i.e. publicKeyToken=”null”), no matter how you implement the class instantiation in the factory class implementation, on the second request, the version portion will be ignored and you’ll get back the instance of the object you created the first time around. For example, if the first request is for the version 1.0.0.0 and the second is for 2.0.0.0, in both cases, you’ll get back the 1.0.0.0 implementation.

Moreover, if you use probing, you’ll always get the first file name match regardless of the version.

The solution is simple – use a key to sign your assembly.

Also, beware that if you’re using probing you must use Assembly.LoadFrom to avoid type mismatch type of exceptions in cases where the first match is not of the right version. Or, simply use codebase hints instead (my personal preference).