You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ETABS插件集成Prism模块时透明代理转InnerModuleInfoLoader类型错误

问题描述

开发的是运行在C盘安装的ETABS软件上的插件,插件dll文件名为Combinito.dll,WPF应用基于Prism框架实现,ETABS要求所有插件需以cPlugin函数作为入口点。
未引入模块时插件运行正常,给仅包含空白测试窗口的基础插件添加模块后,编译可以通过,但运行到bootstrapper.Run()步骤时触发运行时错误,错误信息如下:

Exception thrown: 'System.InvalidCastException' in Prism.Wpf.dll An exception of type 'System.InvalidCastException' occurred in Prism.Wpf.dll but was not handled in user code Unable to cast transparent proxy to type 'InnerModuleInfoLoader'.

通过Fusion++工具抓取ETABS启动并运行插件时的dll加载日志,发现Prism.wpf.dll被触发两次加载,第二次加载失败,失败日志如下:

LOG: DisplayName = Prism.Wpf, Version=8.1.97.5141, Culture=neutral, PublicKeyToken=40ee6c3a2184dc59
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files/Computers and Structures/ETABS 19/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = ETABS.exe
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files\Computers and Structures\ETABS 19\ETABS.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf/Prism.Wpf.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf.EXE.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf/Prism.Wpf.EXE.
LOG: All probing URLs attempted and failed.

第一次成功加载的日志对比:

LOG: Appbase = file:///C:/Program Files/Computers and Structures/ETABS 19/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = ETABS.exe
Calling assembly : Combinito, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Program Files\Computers and Structures\ETABS 19\ETABS.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Prism.Wpf, Version=8.1.97.5141, Culture=neutral, PublicKeyToken=40ee6c3a2184dc59
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf/Prism.Wpf.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf.EXE.
LOG: Attempting download of new URL file:///C:/Program Files/Computers and Structures/ETABS 19/Prism.Wpf/Prism.Wpf.EXE.
LOG: Attempting download of new URL file:///C:/Users/moustafa.el-sawy/source/repos/Combinito/Combinito/bin/Debug/Prism.Wpf.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\moustafa.el-sawy\source\repos\Combinito\Combinito\bin\Debug\Prism.Wpf.dll

可以看到失败的加载请求中调用程序集为unknown,且没有尝试到插件所在目录查找dll。
当前Visual Studio解决方案包含两个项目:模块项目和主插件项目Combinito(作为Shell)。

相关代码

cPlugin.cs核心代码

Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();

Bootstrapper.cs代码

public class Bootstrapper : PrismBootstrapperBase
    {
        protected override IContainerExtension CreateContainerExtension()
        {
            return new UnityContainerExtension();
        }

        protected override DependencyObject CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.Register<MainWindowViewModel>();
        }

        protected override void ConfigureViewModelLocator()
        {
            base.ConfigureViewModelLocator();
        }

        protected override IModuleCatalog CreateModuleCatalog()
        {
            // Use local directory as module catalog
            return new DirectoryModuleCatalog { ModulePath = "Modules" };
        }

    }

模块类代码

using Combinito.Modules.LCGenerator.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;

namespace Combinito.Modules.LCGenerator
{
    /// <summary>
    /// Register components of module with Unity/Prism
    /// </summary>
    [Module(ModuleName = "ModuleA")]
    public class LCGeneratorModule : IModule
    {
        
        public void Initialize()
        {

        }
        public void OnInitialized(IContainerProvider containerProvider)
        {
 
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            
        }
    }
}
解决方案思路
  • 注册程序集解析事件解决探测路径问题:宿主程序ETABS的默认AppBase是自身安装目录,不会主动探测插件目录的dll,在cPlugin函数最开头注册AssemblyResolve事件,手动从插件目录加载缺失的程序集:
// cPlugin.cs入口最开头添加
Assembly currentAssembly = Assembly.GetExecutingAssembly();
string pluginDir = Path.GetDirectoryName(currentAssembly.Location);
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    string assemblyName = new AssemblyName(args.Name).Name + ".dll";
    string assemblyPath = Path.Combine(pluginDir, assemblyName);
    if (File.Exists(assemblyPath))
    {
        return Assembly.LoadFrom(assemblyPath);
    }
    // 额外探测Modules目录下的程序集
    string moduleAssemblyPath = Path.Combine(pluginDir, "Modules", assemblyName);
    if (File.Exists(moduleAssemblyPath))
    {
        return Assembly.LoadFrom(moduleAssemblyPath);
    }
    return null;
};
  • 修正模块目录为绝对路径:原代码中ModulePath = "Modules"是相对路径,会被解析为ETABS安装目录下的Modules文件夹,需要改为插件目录下的Modules绝对路径:
protected override IModuleCatalog CreateModuleCatalog()
{
    string pluginDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    string modulePath = Path.Combine(pluginDir, "Modules");
    return new DirectoryModuleCatalog { ModulePath = modulePath };
}
  • 关闭模块加载的跨域代理逻辑:透明代理转换错误是因为Prism默认加载模块时会做跨域检查,你可以直接改用手动注册模块的方式规避自动探测的跨域问题:
protected override IModuleCatalog CreateModuleCatalog()
{
    var catalog = new ModuleCatalog();
    catalog.AddModule(typeof(LCGeneratorModule).Name, typeof(LCGeneratorModule).AssemblyQualifiedName);
    return catalog;
}

内容的提问来源于stack exchange,提问作者MElSawy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 07:36:03