Search code examples
.net.net-2.0assembly-resolution

How does runtime resolve calls to .NET 2.0 SP1 assemblies if only .NET 2.0 RTM is present


We have application built against .NET 2.0 on machine with .NET 2.0 SP1 installed. The application references some standard .NET assemblies included in .NET SP1 (i.e. System.Xml.dll).

If we run this application on computer with .net 2.0 RTM, the application runs fine, it even uses System.Xml.dll assembly. But when it tries to use method that doesn't exist in 2.0 RTM, but exists in 2.0 SP1 the application throws MethodNotFoundException.

My question is : How does the runtime resolve System.Xml.dll at all?

The assemblies versions differs in revision number (but the major, minor and build parts are equals). That means that 2.0 RTM and 2.0 SP1 assemblies are different in terms of assembly binding process. The runtime should try to find System.Xml.dll 2.0.50727.1378, but it only finds 2.0.50727.42. Then assembly binding process should fail because there can't be any Publisher policy or redirection in Machine.config. But binding works fine. How can it be?

Another one question which follows of the problem described above.

We can't force all our clients to install .NET 2.0 SP1 on their computers. If we ship System.Xml.dll from .NET 2.0 SP1, how can we force our application to use System.Xml.dll shipped with our application?

Update 1: Looks like System.Xml.dll version is 2.0.0.0, not 2.0.50727.x. That describes why the Runtime successfully resolves it. But the second question still applies: Can we ship System.Xml.dll from SP1 with our application and force our application to use it?


Solution

  • If there is no acceptable answers I'll post my own. Hope it helps somebody.

    The first question was how does runtime resolves assemblies from service pack.

    I've investigated a little more and have read some articles. I mistakenly have taken a look at AssemblyFileVersion instead of AssemblyVersion. For assemblies in .NET 2.0 SP AssemblyFileVersion is 2.0.50727.1378, and for assemblies from .NET 2.0 RTM it's 2.0.50727.42. Yes, they are different, but it is AssemblyFileVersion, not AssemblyVersion. And assembly binding process uses AssemblyVersion only. But AssemblyVersion is 2.0.0.0 for .NET 2.0 RTM and .NET SPx either. So RTM and SPx assemblies are identical in terms of assembly binding process.

    I'm still interested why MS hadn't shipped service pack's assemblies with incremented AssemblyVersion? They could ship SP's assemblies with corresponding Publisher policies to redirect assembly binding from RTM to SP. And if clients would like to use RTM versions of assemblies, they can ignore publisher policy for particular assemblies. Actually, I think that MS refused to go that way because it would be a total mess if client start to ignore publisher policies on some assemblies and don't ignore on others. Than BCL's assemblies couldn't rely on each other, the whole BCL would become inconsistent.

    The second question was about the possibility to ship .NET 2.0 SP1 assemblies with our product and to redirect assembly binding from RTM assembly to SP's assembly.

    The short answer is "no, it is not possible". But there are 2 possible solutions, but they are quite lame and can be of use only under strict circumstances and in general they are not applicable at all.

    The first solution is to disasm CLR assembly and then build it again but with our public key, or we can omit strong-signing at all. Now we will be able to reference this RTM assembly rather than SP's assembly from GAC.

    The second solution is to replace RTM's assembly in GAC with SP's assembly using the gacutil tool. The /f (force) option must be used.

    Both of these two solutions are very lame. Please, don't use them. In general they can't be used due to some dependencies between assemblies.

    Conclusion

    In our product we downgraded our product so it could work on .NET 2.0 RTM. But we still use some functionality even from .NET 3.x (linq-to-objects, Action, Func). We just ship some of the 3.x assemblies with our product, e.g. System.Core.dll. Mostly we have no problems with this approach. But we also had to decline using Linq-to-Xml because of some unsolvable problems.