Avatar ·

Как включить логирование ошибок привязки сборок (Fusion) в .NET для отладки?

Привет, коллеги! Я пишу приложение на C# (.NET Framework 4.7.2). Недавно столкнулся с проблемой: после обновления одной из сторонних библиотек (Newtonsoft.Json с 12.0.3 на 13.0.1) при запуске вылетает исключение: System.IO.FileLoadException: "Не удалось загрузить файл или сборку "Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed" либо одну из их зависимостей. Найденное определение манифеста сборки не соответствует ссылке на сборку." Вот фрагмент моего кода, где это происходит: ```csharp using Newtonsoft.Json; public class ConfigLoader { public static T LoadConfig(string filePath) where T : class { string json = File.ReadAllText(filePath); return JsonConvert.DeserializeObject(json); // Исключение здесь } } ``` Я уже проверил: 1. В проекте через NuGet установлена версия 13.0.1. 2. В app.config есть bindingRedirect для старой версии, но он не помогает. 3. Проект использует несколько библиотек, и одна из них, видимо, ссылается на старую версию. Гугл говорит, что нужно включить "Fusion Logging" (логирование привязки сборок), но я не понимаю, как это сделать. Где включать? В коде, в реестре, в конфиге? И как потом читать эти логи? Подскажите, пожалуйста, пошаговую инструкцию для новичка. Заранее спасибо! <<>>

Что такое Fusion Logging и зачем он нужен?

Fusion Logging (или логер привязки сборок) — это встроенный механизм .NET Framework, который записывает подробную информацию о том, как CLR (Common Language Runtime) находит и загружает сборки. Когда возникает FileLoadException или BadImageFormatException, эти логи показывают, какую именно версию сборки запрашивает приложение, где среда ищет эту сборку и почему поиск завершается неудачей.

Способ 1: Включение через реестр Windows (рекомендуется для разработки)

Самый надёжный способ — установить значения в реестре. Это включает логирование глобально для всех .NET-приложений на машине (до перезагрузки или до отмены настройки).

  1. Откройте regedit.exe (Пуск → Выполнить → regedit).
  2. Перейдите в ветку: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion. Если ветки нет — создайте её вручную (правой кнопкой по Microsoft → Создать → Раздел).
  3. Создайте параметр DWORD (32 бита) с именем EnableLog и значением 1.
  4. Создайте параметр DWORD с именем ForceLog и значением 1 (чтобы логировать даже успешные привязки).
  5. Создайте строковый параметр REG_SZ с именем LogPath и значением, например, C:\FusionLogs\ (папка должна существовать).

После этого перезапустите ваше приложение. В папке C:\FusionLogs\ появятся файлы вида DefaultDomain.1.log, DefaultDomain.2.log и т.д. Откройте их блокнотом — вы увидите что-то вроде:

*** Assembly Binder Log Entry  (10/05/2023 @ 14:32:15) ***
The operation failed.
Bind result: hr = 0x80131040. No description available.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable  C:\MyApp\MyApp.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
 (Fully-specified)
LOG: Appbase = file:///C:/MyApp/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyApp.exe
...
LOG: Attempting download of new URL file:///C:/MyApp/Newtonsoft.Json.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\MyApp\Newtonsoft.Json.dll
LOG: Entering download cache setup phase...
LOG: Assembly Name is: Newtonsoft.Json, Version=13.0.1.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
LOG: Found assembly version 13.0.1.0. But request was for version 12.0.0.0.
ERR: The assembly reference did not match the found assembly.

Из лога видно, что приложение запрашивает 12.0.0.0, а на диске лежит 13.0.1.0. Теперь понятно, что нужно исправить bindingRedirect в конфиге.

Способ 2: Включение через код (для точечной отладки)

Если не хотите лезть в реестр, можно включить логирование программно в начале Main():

using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        // Включаем логирование в текущую директорию
        AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "app.exe.config");
        // Устанавливаем переменные среды для Fusion
        Environment.SetEnvironmentVariable("FUSIONLOG_PATH", @".\FusionLogs");
        Environment.SetEnvironmentVariable("FUSIONLOGFILE", "fusion.log");
        
        // Ваш код...
        var loader = new ConfigLoader();
        var config = loader.LoadConfig<MyConfig>("config.json");
    }
}

Но учтите: этот метод работает не всегда надёжно, так как некоторые настройки считываются CLR до выполнения вашего кода. Поэтому способ с реестром предпочтительнее.

Как отключить логирование?

После отладки обязательно отключите логирование, иначе оно будет замедлять работу всех .NET-приложений:

  • Удалите параметры EnableLog и ForceLog из реестра (или поставьте 0).
  • Удалите папку с логами.

Бонус: исправление вашей проблемы с Newtonsoft.Json

Добавьте в app.config корректный bindingRedirect:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-13.0.1.0" newVersion="13.0.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Обратите внимание: oldVersion должен перекрывать все запрашиваемые старые версии (от 0.0.0.0 до текущей).

<<>>

Альтернатива: использование утилиты FusLogVw (Fusion Log Viewer)

Если вам неудобно вручную копаться в реестре и текстовых логах, используйте встроенную графическую утилиту FusLogVw.exe. Она входит в состав Windows SDK (например, Windows 10 SDK) и находится в папке:

C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\FusLogVw.exe

Запустите её от имени администратора. В окне утилиты:

  1. Нажмите Settings.
  2. Выберите Enable all binds (логировать все привязки) или Enable binds to disk (только неудачные).
  3. Укажите путь для сохранения логов.
  4. Нажмите OK и запустите ваше приложение.

Логи будут отображаться в реальном времени в таблице. Вы сможете фильтровать по имени сборки, видеть HRESULT ошибки и полный стек вызовов. Это гораздо удобнее, чем читать сотни строк в блокноте.

Важно: Не забывайте отключать логирование через ту же утилиту после завершения отладки — нажмите Disable в настройках.

Если у вас нет Windows SDK, скачайте его с официального сайта Microsoft (бесплатно). Это также даст вам доступ к другим полезным инструментам, таким как CorFlags.exe и G