.net - 在 GAC 之外的 COM+ 应用程序中注册 .NET 程序集

标签 .net wix windows-installer com+ servicedcomponent

我开发了一个 .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+ 应用程序,在 COM+ 应用程序中注册 MyComPlusAssembly.dll 文件并在其中注册所有 ComVisible 组件,因此在 dcomcnfg 中一切都是可见的并按预期配置.此命令还将生成一个全新的 TLB 文件。
该程序集是使用 AnyCPU 构建的,因此在 x64 版本的 Windows 上,dllhost.exe 进程将作为 64 位运行,而在 x86 版本的 Windows 上它将作为 32 位运行。另外,我的 dll 文件应该是 不是 放在 GAC 中(这就是我使用 RegSvcs.exe 命令行实用程序的/appdir 开关的原因)。使用上述批处理文件安装 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 后立即回滚。
可以在日志中找到以下错误(对于 BOTH 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

上述错误可能表示COM+应用程序中注册的dll丢失,即文件不在磁盘上。
虽然安装过程很快,但我从未见过 MyComPlusAssembly.dll 文件被复制到磁盘(到 [INSTALLDIR_SERVER]),当安装开始回滚(包括 TLB)时,所有其他文件都在磁盘上。这是时间问题吗?

观察:
  • 这对于安装程序的两个版本(x64 和 x86)都会发生。
  • 当删除“<complus:ComPlusAssembly...>”标签(包括
    嵌套组件),安装成功并出现(空)
    应用程序被创建,即 - 只有容器”,没有任何
    程序集或 COM+ 托管组件。
  • 我尝试添加第三个“<Component.../> ”,它创建了一个简单的
    注册表项并移动所有
    <complus:ComPlusApplication.../> ” 代码。该组件将
    复制所有文件后执行。与日志相同的结果(错误)
    以上。

  • 我在这里缺少什么?

    最佳答案

    这对我有用:

    <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 属性?

    编辑:这是在 Windows XP 和 Windows 2008 32 位上的 Wix v3.6 上。要确保的另一件事是您还安装了 COM+ 组件所需的所有依赖项。使用 Assembly Binding Log Viewer在安装期间查看您的组件是否由于缺少或不正确(错误的版本)依赖项而无法加载。

    关于.net - 在 GAC 之外的 COM+ 应用程序中注册 .NET 程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13944373/

    相关文章:

    WiX - 在两个不同的位置安装相同的文件

    c# - 从 IDataReader 映射时,我可以将 AutoMapper 配置为从自定义列名读取吗?

    wix - 绑定(bind) WIX FileVersion 子值?

    c++ - 如何从 C++ 自定义操作获取 MSI 'UILevel' 属性

    visual-studio-2010 - Visual Studio 2010 抛弃了 Wix?

    windows - 字体文件被系统进程占用

    visual-studio-2008 - 我是否应该在每次构建时更改我的 .vdproj 文件中的 ProductCode?

    c# - 如何从正则表达式中获取匹配的字符串? [C#]

    .net - 使用 .Net Core Web Api 中的 Azure B2C 处理密码重置

    .net - 带有用于角色授权的空格的 AD 组