Регистрация сборки.NET в приложении COM+ вне GAC
Я разработал сборку.NET (.NET 4.0 со строгим именем), которая предоставляет два обслуживаемых компонента. Сборка (dll) должна быть размещена в приложении COM+ и украшена атрибутами COM+ (сборка и уровни компонентов). Например, атрибуты уровня сборки:
//COM+ Attributes
[assembly: ApplicationID("MY_APP_GUID")] //GUID of the COM+ app
[assembly: ApplicationName("MyComPlusAppName")] //Name of the COM+ app
[assembly: ApplicationActivation(ActivationOption.Server)] //The app is hosted in it own dllhost process (out-of-process)
[assembly: ApplicationAccessControl(AccessChecksLevel = AccessChecksLevelOption.ApplicationComponent, Authentication = AuthenticationOption.None, ImpersonationLevel = ImpersonationLevelOption.Delegate, Value = false)]
[assembly: Description("COM+ app description")]
В настоящее время (по причинам разработки) я запускаю следующий скрипт для создания приложения COM+ и регистрации сборки (со всеми ее компонентами):
%windir%\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exe /appdir:"%CD%" MyComPlusAssembly.dll
Приведенный выше пакетный файл создаст (за один раз) приложение COM+ в соответствии с атрибутами оформления сборки, зарегистрирует файл MyComPlusAssembly.dll в приложении COM+ и зарегистрирует в нем все компоненты ComVisible, так что все будет видно и настроено так, как ожидается в dcomcnfg., Эта команда также создаст новый новый файл TLB. Сборка построена с использованием AnyCPU, поэтому в 64-разрядных версиях Windows процесс dllhost.exe будет работать как 64-разрядный, а в 32-разрядной версии Windows - как 32-разрядный. Кроме того, мой файл DLL не должен быть помещен в GAC (вот почему я использую ключ /appdir утилиты командной строки RegSvcs.exe). Все работает как положено при установке сборки COM+ с помощью вышеуказанного командного файла.
Я начал писать проект развертывания Wix (v3.6) для моего приложения, который должен делать то же самое: создать приложение COM+, зарегистрировать сборку.NET и все компоненты ComVisible. Обратите внимание, что на этот раз я полагаюсь на тот факт, что файл TLB поставляется с установщиком (*.msi). TLB был сгенерирован процессом сборки (VS 2010). Для достижения вышеизложенного я добавил следующий компонент Wix (вдохновленный документами по расширению Wix COM+ - WixComPlusExtension):
<DirectoryRef Id="INSTALLDIR_SERVER">
<Component Id="cmp_MyComPlusAssembly.dll" Guid="COMPONENT_DLL_GUID">
<File Id="MyComPlusAssembly.dll" Name="MyComPlusAssembly.dll" DiskId="1" Source="..\install\$(var.Configuration)\Server\MyComPlusAssembly.dll" KeyPath="yes"/>
<CreateFolder>
<util:PermissionEx GenericAll="yes" User="NT AUTHORITY\LocalService"/>
</CreateFolder>
<complus:ComPlusApplication Id="ComPlusServerApp"
AccessChecksLevel="applicationComponentLevel"
Activation="local"
ApplicationAccessChecksEnabled="no"
ApplicationDirectory="[INSTALLDIR_SERVER]"
ApplicationId="MyComPlusAssembly.dll"
Authentication="none"
Description="MyComPlusAssembly.dll"
Identity="NT AUTHORITY\LocalService"
ImpersonationLevel="delegate"
IsEnabled="yes"
RunForever="yes"
Name="MyComPlusApp"
Deleteable="yes">
<complus:ComPlusAssembly Id="ComPlusServerAssembley"
DllPath="[#MyComPlusAssembly.dll]"
TlbPath="[#MyComPlusAssembly.tlb]"
Type=".net"
DllPathFromGAC="no">
<complus:ComPlusComponent Id="COMObject_1"
CLSID="COM_OBJ_1_GUID"
Description="Object 1"
IsEnabled="yes"/>
<complus:ComPlusComponent Id="COMObject_2"
CLSID="COM_OBJ_2_GUID"
Description="Object 2"
IsEnabled="yes"/>
</complus:ComPlusAssembly>
</complus:ComPlusApplication>
</Component>
</Component>
<Component Id="cmp_MyComPlusAssembly.tlb" Guid="COMPONENT_TLB_GUID">
<File Id="cmp_MyComPlusAssembly.tlb" Name="cmp_MyComPlusAssembly.tlb" DiskId="1" Source="..\install\$(var.Configuration)\Server\cmp_MyComPlusAssembly.tlb" KeyPath="yes"/>
</Component>
</DirectoryRef>
Проект MSI строится успешно, но процесс установки завершается неудачно и откатывается сразу после попытки зарегистрировать dll. Следующая ошибка может быть найдена в журнале (для ОБА версии x86 и x64):
Action 16:33:37: RegisterComPlusAssemblies. Registering COM+ components
RegisterComPlusAssemblies: DLL: C:\Program Files\MyApp\Server\MyComPlusAssembly.dll
ComPlusInstallExecute: Registering assembly, key: ComPlusServerAssembley
ComPlusInstallExecute: ExceptionInfo: Code='0', Source='System.EnterpriseServices', Description='Failed to load assembly 'c:\program files\myapp\server\MyComPlusAssembly.dll'.', HelpFile='', HelpContext='0'
ComPlusInstallExecute: Error 0x80020009: Failed to invoke RegistrationHelper.InstallAssembly() method
ComPlusInstallExecute: Error 0x80020009: Failed to register .NET assembly
ComPlusInstallExecute: Error 0x80020009: Failed to register assembly, key: ComPlusServerAssembley
ComPlusInstallExecute: Error 0x80020009: Failed to register assemblies
Вышеуказанная ошибка может означать, что dll, регистрируемая в приложении COM+, отсутствует, то есть файл отсутствует на диске. Хотя процесс установки быстрый, я никогда не видел, чтобы файл MyComPlusAssembly.dll копировался на диск (в [INSTALLDIR_SERVER]), но все остальные файлы находятся на диске, когда установка начинает откатываться (включая TLB). Это проблема времени?
Замечания:
- Это происходит для обеих версий установщика (x64 и x86).
- При удалении
<complus:ComPlusAssembly...>
"тег (включая вложенные компоненты), установка завершается успешно и создается (пустое) приложение, то есть - только контейнер", без каких-либо сборок или компонентов COM+. - Я пытался добавить третий "
<Component.../>
"который создает простой ключ реестра и перемещает все"<complus:ComPlusApplication.../>
"код к нему. Этот компонент будет выполнен после того, как все файлы будут скопированы. Тот же результат (ошибка), что и в журнале выше.
Что мне здесь не хватает?
3 ответа
Я изменил целевую платформу сборки COM+ на 3.5, и это сработало.
Проблема заключается в версии System.EnterpriseServices.dll, вызываемой из WixComPlusExtension. Существует несколько версий библиотеки, по крайней мере: 2.0.xxxx и 4.0.xxxx. WixComPlusExtension вызывает метод RegisterDotNetAssembly (cpasmexec.cpp), который использует класс System.EnterpriseServices.RegistrationHelper для регистрации сборки. Дело в том, что при вызове RegistrationHelper.InstallAssembly из System.EnterpriseServices версии 2.0.xxxx для библиотеки.net COM+, созданной для платформы 4 или выше, появляется ошибка "Не удалось загрузить сборку".
Любые идеи, как настроить WixComPlusExtension (это с открытым исходным кодом), чтобы он вызвал System.EnterpriseServices для framework 4?
Это работает для меня:
<Component Id="cmp502C27298171EA4E966A386B188D734C" Guid="{7A5ADAA7-8D43-4E91-80DB-764BB1E13887}">
<File Id="filB4BA1D295EA5EC7D92FD7FEFDD1251C2" KeyPath="yes" Source="$(var.BinComPlusFolder)\MyComponent.dll" />
<complus:ComPlusApplication Id="MyApp" Name="MyApp" Description="My App" ApplicationAccessChecksEnabled="no" AccessChecksLevel="applicationComponentLevel" Authentication="packet" ImpersonationLevel="impersonate" Activation="local" ApplicationDirectory="[ServicesBinFolder]" Identity="[SERVICE_USERNAME]" Password="[SERVICE_PASSWORD]" ShutdownAfter="3" Deleteable="yes" CRMEnabled="yes" ThreeGigSupportEnabled="no" ConcurrentApps="3" RecycleLifetimeLimit="60" RecycleMemoryLimit="500000" RecycleExpirationTimeout="15" RecycleCallLimit="0" RecycleActivationLimit="0" DumpEnabled="no" DumpOnException="no" DumpOnFailfast="no" DumpPath="%systemroot%\system32\com\dmp" QueuingEnabled="no" />
<complus:ComPlusAssembly Id="filB4BA1D295EA5EC7D92FD7FEFDD1251C2" Application="MyApp" DllPath="[#filB4BA1D295EA5EC7D92FD7FEFDD1251C2]" TlbPath="[#fil447CD49CDBE45EACEE125A362902CF2F]" Type=".net" RegisterInCommit="yes" />
</Component>
Возможно, вам следует пропустить атрибут DllPathFromGAC?
Изменить: Это на Wix v3.6 на Windows XP и Windows 2008 32bit. Другая вещь, которую нужно гарантировать, это то, что вы также устанавливаете все зависимости, требуемые компонентом COM+. Используйте средство просмотра журнала привязки сборки во время установки, чтобы проверить, не загружается ли ваш компонент из-за отсутствующих или неправильных (неправильных версий) зависимостей.
Кажется, есть много примеров этого, но даже если вы будете следовать им, вы не сможете добиться успеха.
Вот как я это сделал:
После компиляции и ссылки cl *.cs -o foo.dll
tlbexp foo.dll
heat file foo.dll -o foodll.wxs
heat file foo.tlb -o foodlltlb.wxs
Некоторые вручную редактируют файл foodlltlb.wxs, потому что сгенерированный wxs из-за жары будет генерировать предупреждения / ошибки со свечой (3.8) (Basic, TypeLib должен быть дочерним элементом File)
Исправьте ваш идентификатор guid и компонента, укажите их в главном wxs, вуаля!