Возникла ошибка BadImageFormatException с узлом WcfSvcHost и IIS WCF

Создание библиотеки служб WCF в Visual Studio 2008 в Vista x64 проблематично при обращении к библиотеке x86. Служба, которая вызывает 32-битную DLL, должна иметь целевую платформу x86 для работы в 64-битной ОС. Когда вы делаете это, WcfSvcHost выдает исключение BadImageFormatException при попытке отладки службы. На MS connect есть сообщение об ошибке. Обходной путь, который я использовал, состоял в том, чтобы установить флаг WcfSvcHost как 32-битный.

Проблема с манифестом

Основная проблема, с которой я столкнулся, заключается в том, что эту стороннюю 32-битную DLL не удается загрузить с помощью определенных хостов WCF. Я получаю следующую ошибку, когда вызывается операция службы, использующая стороннюю DLL:

System.TypeInitializationException: инициализатор типа для '' вызвал исключение.

.ModuleLoadExceptionHandlerException: вложенное исключение произошло после основного исключения, которое вызвало сбой загрузки модуля C++.

System.BadImageFormatException: модуль должен содержать манифест сборки. (Исключение из HRESULT: 0x80131018)

NestedException:

Дескриптор недействителен. (Исключение из HRESULT: 0x80070006 (E_HANDLE))

Это исключение не возникает при запуске WcfSvcHost, оно вызывается при запуске операции службы, которая ссылается на 32-разрядную DLL. Что очень интересно, хостинг этого же сервиса с тем же app.config в консольном приложении не имеет исключений и работает отлично:

using (ServiceHost host = new ServiceHost (typeof (MsgBrokerService))) {
    host.Open ();
    Console.WriteLine ("running");
    Console.ReadLine ();

Это исключение возникает сразу после:

"WcfSvcHost.exe" (управляемый): загружен "C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_ none_d08d7bba442a9b36\msvcm80.dll"

Опять же, консольное приложение не имеет исключения и загружает ту же DLL:

'ConsoleApp.vshost.exe' (управляемый): загружен 'C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_ none_d08d7bba442a9b36\msvcm80.dll'

См. Ответ службы поддержки продуктов Microsoft.

Обновление № 1: и консольное приложение, и хост-процесс WcfSvcHost.exe выполняются в одном сеансе и вошли в систему (я). Я скопировал WcfSvcHost.exe в каталог службы, запустил вручную и получил тот же результат. Я также проверил журнал событий Windows для дополнительной информации и использовал sxstrace, но ничего не было зарегистрировано.

Запустив Process Explorer, я убедился, что между двумя процессами одно и то же:

  • Изображение: 32-разрядное
  • Текущий каталог
  • Пользователь /SID
  • сессия
  • Безопасность (группы запрещены, привилегии отключены)

Запустив Process Monitor и настроив символы, я вижу, что WcfSvcHost ищет следующий реестр и файлы, а консольный хост - нет. Process Monitor регистрирует много данных, и я не уверен, что я ищу:(.

HKLM \ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ \Microsoft\Fusion\PublisherPolicy\Default\policy.8.0.msvcm80__b03f5f7f11d50a3a C:\Windows\ Assembly\GAC_32\msvcm80\8.0.50727.3053__b03f5f7f11d50a3a C:\Windows\ 27.30: ff_50_f_50_f_50_f_50_50_50_50_f_3_50_f_3_50_50 как_байт_файлах:: C3_3: c: 80: 80 \ f50_50_50_50_50_f_50_50_50_50: \: c: 80: \ \ 803: C: Windows \ сборка \GAC\msvcm80\8.0.50727.3053__b03f5f7f11d50a3a

Обновление № 2. Это же исключение возникает, когда служба размещена в рабочей среде на IIS 6 / Windows Server 2003.

Обновление №3. Сторонней 32-разрядной сборкой.NET является API-интерфейс StreamBase:

  • sbclient.dll (управляемый)
  • monitor.netmodule (управляемый)
  • dotnetapi.dll (неуправляемый)
  • pthreads-vc8.dll (неуправляемый)

Обновление № 4: добавлены манифесты без успеха:

  1. Проверено, что dotnetapi.dll и pthreads-vc8.dll имеют RT_MANIFEST. Сборка sbclient.dll .NET не имела манифеста
  2. Удален sbclient.dll из GAC
  3. Зарегистрированный sbclient.dll для проверки пропуска
  4. Добавлен манифест через mt.exe как для sbclient.dll, так и для monitor.netmodule
  5. Был добавлен проверенный манифест и ожидаемые файлы были загружены во время тестирования (через Visual Studio - окно отладочных модулей)
  6. То же BadImageFormatException генерируется в BackgroundWorker.OnDoWork(), а стек вызовов показывает вызов dotnetapi.dll...DefaultDomain.Initalize().

Я проверил, что msvcm80.dll не имеет манифеста, я считаю, что это единственный загруженный файл, который не имеет манифеста:)

Интересная находка

Когда я загружаю monitor.netmodule в Reflector, он говорит:

'monitor.netmodule' не содержит манифеста сборки.

Несмотря на то, что он отображает ошибку, Reflector все еще может разобрать управляемый код.

7 ответов

Решение

Служба поддержки продуктов Майкрософт решила этот вопрос: это сделано специально. Неуправляемый код не загружается в AppDomain по умолчанию при использовании WcfSvcHost или хоста IIS WCF.

Чистый образ будет использовать CLR-версию библиотеки времени выполнения C. Однако CRT не поддается проверке, поэтому вы не можете использовать CRT при компиляции с /clr:safe. Для получения дополнительной информации см. C Run-Time Libraries.

http://msdn.microsoft.com/en-us/library/k8d11d4s.aspx

Немного поздно, но вы также можете изменить настройку пула приложений "Включить 32-битные приложения" на true в расширенных настройках.

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

Не могли бы вы вручную добавить манифест в эту DLL, используя файл mt.exe?

MSDN Статья об использовании mt.exe

Видите ли вы что-то особенное в окне просмотра событий?
В Vista, если есть явная проблема, вы увидите ее след в средстве просмотра событий, оно скажет вам использовать SxsTrace.

Столкнулся с этим вопросом сам. Я нашел полезный пост. Как отмечалось в других постах, Microsoft заявила, что это сделано специально. В основном вам нужно:

  1. Найдите вашу версию WcfSvcHost.exe. (для меня и Visual Studio 2017: C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE)

  2. Запустите командную строку разработчика

  3. Выполнить cmd: copy C:\SourcePath\WcfSvcHost.exe C:\DestinationPath\WcfSvcHost32.exe (Пункт назначения не имеет значения)

  4. CMD: corflags /32BIT+ /Force WcfSvcHost32.exe (может понадобиться перейти к DestinationPath

  5. В Visual Studio откройте свойства проекта WCF> вкладка "Отладка"> "Запустить внешнюю программу": C:\DestinationPath\WcfSvcHost32.exe

  6. Также добавьте свои аргументы командной строки:

    /service:MyWCFProjectName.dll /config:MyWCFProjectName.dll.config

    Примечание: вам не нужно использовать ($ProjectDir) Вот

  7. Запустите приложение. Теперь вы можете запускать WcfServiceHost.exe отдельно.

  8. При необходимости перейдите к решению> Задать стартовые проекты> Несколько стартовых проектов> Выберите проект Wcf и проект клиента.

Я не могу предоставить объяснение этой ошибки, только мое первоначальное подозрение, что существует разница в разрешениях между контекстом, в котором ваш код запускается как служба, и контекстом, в котором он запускается, когда вы помещаете его в консольное приложение. E_HANDLE HRESULT - моя подсказка. Предполагая, что вы запускаете консольное приложение как вошедший в систему пользователь, вы можете попытаться настроить службу так, чтобы она также запускалась от имени этого пользователя. Если он работает в этой конфигурации, вы можете попытаться сузить необходимый ресурс, недоступный в случае сбоя.

Я могу предложить обходной путь. Если есть какая-то странность рассматриваемой DLL, которая мешает ей работать в размещенной службе, вы можете использовать метод жертвенного процесса, названный так потому, что он обычно используется для изоляции DLL, которая часто выходит из строя. Вкратце, вы создаете прокси-программу, единственная цель которой - загружать и вызывать DLL от имени вашего основного процесса, используя именованные каналы или какой-либо другой метод IPC для передачи запросов и результатов. В случае сбоя DLL вы запускаете новый экземпляр прокси-программы. В вашем случае было бы дополнительное преимущество, что только программа-обертка должна быть 32-битной.

Другие вопросы по тегам