.Net Compact Framework: Versioning, Strong Names and the Global Assembly Cache – Part 1

Hi everyone – My name is Steven Pratschner.  I’m the Program Manager for the CLR that ships as part of the .Net Compact Framework.  I intend to use this blog to post information on various topics related to the Compact Framework, including versioning, interop, diagnostics, performance and so on.  In many cases I’ll cover topics that either haven’t been covered by the formal product documentation yet or are new in the publicly available pre-releases of Whidbey.  I’ll also look at features that behave slightly differently in the Compact Framework than they do on the full .Net Framework.

This is the first of several posts related to how versioning and deployment work in Compact Framework applications.  In this post I’ll point out the semantic differences between the versioning system present in the Compact Framework and the versioning system used in the full .Net Framework.  The information presented in this post applies only to version 1.0 of the Compact Framework.  In future posts I’ll cover more about how to use the Global Assembly Cache (GAC) in your applications, how the GAC is implemented by the Compact Framework, how side-by-side works in the Whidbey pre-releases and so on.

At a high level, the versioning and deployment system provided by the Compact Framework has the same goals and many of the same building blocks as the corresponding feature set in the full .Net Framework.  The Compact Framework has a GAC, it relies on strong names for assembly identity and version binding and it encourages a private deployment model by default.  Deploying an assembly to the same directory as the application that uses it keeps the assembly private to that application and frees you from thinking about the implications of providing an assembly that will be shared by many applications.  The concept of a shared assembly exists in the Compact Framework just as it does in the full .Net Framework, however.  In order to share an assembly among multiple applications you must give that assembly a strong name and deploy it to the GAC.  Building an assembly that is shared by multiple applications also brings with it the burden of servicing the assembly independent of any application that is using it.

Despite the similarities in the overall model, the implementation provided by the Compact Framework has a few key differences to be aware of if you’re used to writing applications for the full .Net Framework.  In particular:

1.      Strong name signatures are verified each time an assembly is loaded from the GAC.

2.      Delay signing is not suppored.

3.      The default version binding rules are different.

4.      Binding redirects cannot be specified.

5.      There are fewer rules for finding an assembly under the application directory.



Strong Name Signature Verification

On the full .Net Framework, the strong name signatures for assemblies that are added to the GAC are verified only at install time, not each time the file is loaded.  The GAC for the full .Net Framework is stored under the Windows directory, which is secured (with ACL’s) so it can only be accessed by Administrators.  Because the GAC is in a secure location, verifying the strong name signature only when the assembly is installed to the GAC is considered sufficient.  This helps with performance because the signatures for files in the GAC don’t need to be verified each time the file is loaded.

In contrast, the Compact Framework’s GAC is not considered secure because Windows CE (at least not all configurations) doesn’t support ACL’s which are required to restrict access to the GAC.  As such, the Compact Framework verifies the strong name signatures for files in the GAC each time the file is loaded.  Although verifying signatures on every load impacts performance, this extra precaution is necessary to ensure that an assembly in the GAC can’t be tampered with between the time it was installed and the time in which it is used.


Delay Signing

The full .Net Framework provides a feature called “delay signing” that makes it easier to build strong named assemblies in scenarios where you don’t have direct access to the private key during development.  Delay signed assemblies can be run on your development machine as long as you’ve disabled strong name verification for your assembly using the sn.exe SDK tool.

The .Net Compact Framework has no support for running delay signed assemblies.  All strong named assemblies must have complete signatures in order to be loaded and executed.


Default Version Binding Rules

Both the full .Net Framework and the Compact Framework check version numbers when resolving references to assemblies with strong names.  However, the rules for which parts of the version number must match the reference differ between the two implementations.

All .Net assemblies have a version number consisting of four parts: <major>.<minor>.<build>.<revision>.  The full .Net Framework requires all four parts of the version number to match in order to satisfy a reference to a strong named assembly. 

In contrast, the .Net Compact Framework allows the revision portion of the version number to “float” when resolving references to strong named assemblies.  For example, say you have an application compiled against version of an assembly called Strong.  When the Compact CLR looks in the GAC to resolve the reference, it will load the assembly with the highest revision number (assuming a major.minor.build or 5.0.0, of course).  So if versions and are both deployed to the GAC, version will be loaded.  The reason the Compact CLR has this extra flexibility is to make it easier for assemblies to be serviced independent of the applications they were shipped with.  The need for this additional flexibility is required in part by the lack of ability to specify version redirects as we’ll see in the next section.

It’s also worth noting that the Compact Framework prefers to load a strong named assembly from the GAC (instead of the app directory) just as the full .Net Framework does.  This can impact the previous scenarios as follows.  Say that version of Strong were deployed to the GAC, but version were deployed to the same directory as the application that references it.  The Compact CLR will begin by looking for an assembly with a major.minor.build number of 5.0.0 in the GAC.  If one is found, that assembly is loaded and searching stops.  In our scenario, even though version has a higher revision number, it will not be loaded because an assembly that satisfies the reference (version was found in the GAC first.


Version Binding Redirects

The default version binding behavior can be customized on the full .Net Framework by specifying “binding redirects” in XML configuration files.  For example, if an application was built against version of a given strong named assembly, you can use a configuration file to cause version to be loaded instead.

The .Net Compact Framework does not have the concept of configuration files, so binding redirects cannot be specified.  Instead, the exact version of the assembly you built against (modulo the revision number as discussed above) will be loaded at runtime.  No more customizations are possible.


Probing Rules

Both the Compact Framework and the full .Net Framework search for assemblies in the application directory by matching the assembly’s friendly name to a file name with a .dll extension.  For example, when resolving a reference to an assembly named Weak, both products start by looking for a file named Weak.dll in the same directory as the application that is running. 

This simple rule of looking directly in the application directory is the only step the Compact Framework takes to load an assembly with a weak name.  The full .Net Framework has many other rules, including searching subdirectories based on the assembly name, the ability to customize the search path using either configuration files or application domain properties and so on.  None of these options are available on the .Net Compact Framework.  If an assembly with the required file name is not found in the application directory, an exception is thrown and searching stops.


That’s it for now.….




Disclaimer: This posting is provided “AS IS” with no warranties, and confers no rights

Comments (5)

  1. Welcome aboard! And, thanks for the intro into these important security topics as related to the Compact Framework.

  2. Chris Auld says:

    I’d be keen to see some stuff on how the GC differs from the desktop framework.

  3. Neil Cowburn says:

    This is all good stuff! Keep it coming. The info about version binding granuality should be required reading for all .NET Compact Framework developers.

    When I was looking into implementing a GAC installed of the OpenNETCF assemblies for the Smart Device Framework, I ultimately took a different approach to versioning. The reason for this is I didn’t want to have a bunch of assemblies with the same significant version signature (major.minor.build) in GAC. Instead, I opted to use a fixed AssemblyVersion and for our internal version tracking we would use the Win32 File Version number and increment this on each build.

    Of course, using the fact that the revision field is insignificant in version binding, it means we can easily drop hot fixes and revisions into the GAC as and when we see fit. That said, we’ve not had the need to that so far.