Fusion handles missing assemblies poorly

Junfeng Zhang’s .NET Framework notes (http://blogs.msdn.com/junfeng/archive/2005/06/03/424680.aspx) referenced a bug logged against Fusion and answered as “Won’t Fix”. I do not think that Microsoft has correctly understood or responded to the problem.

Here’s a quick summary of the bug:

  • Install two assemblies Binding.exe and ClassLibrary1.dll, with Binding dependent upon ClassLibrary1.
  • Delete ClassLibary1.dll.
  • Launch Binding.
  • MSI is not invoked for a repair, and the load fails with “Unhandled Exception: System.IO.FileNotFoundException: File or assembly name ClassLibrary1, or one of its dependencies, was not found.”

The problem is that Fusion allows the assembly binding to fail rather than invoke MsiProvideAssembly (…INSTALLMODE_DEFAULT…). The MSDN article describing how assemblies are located says that “If the assembly is not found after probing, the runtime requests the Windows Installer to provide the assembly.” This is referring to dependent assemblies, not to how Fusion attempts to locate assemblies directly invoked via Explorer.

Junfeng Zhang’s response is:

“We don’t invoke MSI install every time we see a binding failure. There are many by-design binding failure for resource probing. If we do that the perf will go to hell.

Instead, we query MSI before we invoke MSI install. If MSI says it has the component we then will invoke MSI install. In John’s case, the query returns nothing because ClassLibrary1.dll is in the wrong context/component.”

To address each point without hijacking that post. . .

There are certainly by-design binding failures, but these are most often for .resource assemblies, and do not result in a final Unhandled Exception attempting to load (right?). In this case, Fusion knows that the assembly is going to fail to load and that it is because there was an unhandled exception while attempting to load a dependency. The probing process already consumes significant time at this point, so investing additional time necessary to ask MSI to provide the assembly and repair if necessary seems like a good return on investment. The only time we’d take the hit of actually running a repair would be when MsiProvideAssembly detects that a repair is necessary.

Without knowledge of Fusion’s implementation, I can only speculate about how they are querying MSI in this scenario to see if it “has the component”. It doesn’t appear that Fusion ever loads MSI into it’s process, and no separate msiexec process is started. If Fusion used MsiProvideComponent (…INSTALLMODE_DEFAULT…) then the directly invoked assembly and any components in the component’s feature or feature parent would be reinstalled. Even if Fusion is somehow querying MSI in this scenario, doing so for only the directly invoked component would be almost useless in a real-world scenario. Very rarely would we have an assembly with no dependencies.

I’m not sure what “the query returns nothing because ClassLibrary1.dll is in the wrong component” means. MSI only allows one assembly per component, so I assume that “wrong component” just means “not the component we’re specifically verifying”. Even that is suspect, however, since a Component’s state can only be accurately evaluated in the context of a Feature. The “wrong” thing here seems to be Fusion’s implementation of the described functionality. Fusion should be using the MsiProvideComponent method rather than directly referencing a component out of the context of the associated feature.

The best solution would seem to be that if an assembly fails to bind dependencies after probing, the runtime requests that Windows Installer provide the assembly; the same solution that the documentation indicates has been implemented.

What do you think?