Investigating .NET assembly loading (binding) issues
Once in a while, you encounter that peculiar problem when you run your application and receive an exception saying TypeLoadException or FileNotFoundException even though the DLLs that your application relies on, are right there!
The first suspect that may jump to your head is an assembly binding issue since it happens at the moment you run your application. It might be a mix of old DLLs with new ones, mismatch in version numbers or cultures, missing assemblies at the application’s folder, or even a probing failure, either of each — fusion log viewer can assist in identifying the case.
This lifesaving tool is installed as part of Visual Studio installation on your development system and has to run with administrator privileges.
According to MSDN, this viewer:
The Assembly Binding Log Viewer displays details for assembly binds. This information helps you diagnose why the .NET Framework cannot locate an assembly at run time. These failures are usually the result of an assembly deployed to the wrong location, a native image that is no longer valid, or a mismatch in version numbers or cultures.
The basics
I highly recommend to change the default log location (at Internet Explorer cache) into a custom clean folder; this can be done on the ‘Log Settings’ dialog. Thus you bypass issues with the default location that causing the log to stop showing new entries because IE cache can get corrupted and prevent read and write operations by the .NET binding infrastructure.
Personally, I prefer to log only binding failures. In such a way, I’m able to see only the required information for understanding my problem, prevent disk flooding, and causing each .NET application slowdown (since logs are being gathered). Once turned on, you can immediately identify your failure. Just double click on the selected entry and the following information will be displayed:
The specific reason the bind failed, such as “file not found” or “version mismatch”.
Information about the application that initiated the bind, including its name, the application’s root directory (AppBase), and a description of the private search path, if there is one.
The identity of the assembly the tool is looking for.
A description of any Application, Publisher, or Administrator version policies that have been applied.
Whether the assembly was found in the global assembly cache.
A list of all probing URLs.
Below a synthetic example I created:
\*\*\* Assembly Binder Log Entry (2020–01–26 @ 16:28:09) \*\*\*
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Example.exe
— — A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = Foo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = Example.exe
Calling assembly : Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Foo.DLL.
LOG: Attempting download of new URL file:///C:/Foo/Foo.DLL.
LOG: Attempting download of new URL file:///C:/Foo.EXE.
LOG: Attempting download of new URL file:///C:/Foo/Foo.EXE.
LOG: All probing URLs attempted and failed.
\*\*\* Assembly Binder Log Entry (2020–01–26 @ 16:28:09) \*\*\*
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Example.exe
— — A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = Foo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = Example.exe
Calling assembly : Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Foo.DLL.
LOG: Attempting download of new URL file:///C:/Foo/Foo.DLL.
LOG: Attempting download of new URL file:///C:/Foo.EXE.
LOG: Attempting download of new URL file:///C:/Foo/Foo.EXE.
LOG: All probing URLs attempted and failed.
According to the log, the assembly binder searches for Foo, whether it is a DLL or an executable. First, it looks for an application configuration file to understand where to load its dependencies (probing), when it can’t find it, the default host configuration is loaded and then looks for Foo locally. When not found, an exception is being thrown.
You can do additional basic operations such as delete one entry or all of them and refresh the interface to get new entries.
Furthermore, you can bind for native images created by Ngen (Native Image Generator), under the ‘Log Categories’ group. If you desire to get details of apps running in the Windows app container, then enable the immersive logging option.
Fusion++
Thanks to Andreas Wäscher, we don’t have to deal with all of these settings. He developed, in his own words, a modern alternative for fusion log viewer, named Fusion++ that can be downloaded from here:
Dev tools and great UX don’t have to be mutually exclusive
Did you ever have the pleasure to analyze assembly binding logs in .NET? You came here by yourself so I assume you know the good old FUSLOGVW.exe.
So, do you know what "Enable immersive logging" means? Or why you should separate log categories from "Default" and "Native Images" Did you ever forget to disable the log again and wondered why every .NET application was that slow and your disk ran out of space?
Introducing Fusion++
Forget all the setup upfront - just hit "Record" to capture your assembly logs. If you are done, click "Stop" again. That's it.
Fusion++ then parses all the log files for you. It will try to find warnings and errors and highlight the parsed records in the UI accordingly*. There's no need to go hunting in the file system anymore.
Fusion++ makes sure…
After running it, just hit the ‘Record’ button to capture assembly logs, and when done, click on ‘Stop.’ His app parses all the log files, highlights the parsed warning and failure to quickly identify issues, as seen below in the same tailored failure example:
Look how easy to find what went wrong. An error line is marked in red, and when you double click on it, you can see the loading failure.
Furthermore, logs are being saved into the Windows Temp folder to easily clean them using ’Cleanup Windows Tools,’ besides it allows seeing previously recorded sessions. More advanced features are the grid annotations that indicate events over the app scrollbar and the parser range selector.
To conclude, Assembly load failures and binding redirects can make any .NET developer frustrated, thus this open-source desktop app touches a soft spot and acts as a real game-changer. It allows you to spend your time wisely, instead of diagnosing binding errors. So, go ahead and use it.
Top comments (0)