避免将多个版本的程序集加载到同一个上下文中

时间:2011-11-03 23:10:12

标签: c# .net reflection dll assemblies

这个主题涵盖了我的问题。 我已经看过关于这个问题的最佳实践文档,但它并没有真正描述如何摆脱这种情况。 http://msdn.microsoft.com/en-us/library/dd153782.aspx

我的情况。 路径A: 主要应用。 (签名,版本.net 3.5) 通用接口组件X.(已签名,版本化)

路径B: 用户组装。 通用接口组件X.(已签名,版本化)(可能与上述版本不同。可能不知道实际版本,因为我们无法控制客户/用户的操作。)

我们的主应用程序使用反射从用户程序集加载指定的类,并使用通用接口程序集X中定义的指定接口与类通信。 应用程序必须保留在一个特定路径中,而用户(业务)程序集则保留在另一个路径中。不要让我改变它,它不在我的手中。

问题是,路径B中很可能会有通用接口组件X的副本。 因此,当我使用反射加载用户程序集时,它会自动从同一路径加载Common Interface Assembly X,而不是使用已在应用程序内存中加载的那个。 我最终使用Type iXXX与Type iXXX不同,或者找不到User Assembly类的Constructor,因为它再次混淆了Common Interface Assembly X的两个副本之间的接口。

那么,我怎样才能在路径B中从用户程序集中加载和创建一个类,但是没有从路径B加载公共接口程序集X(并使用路径A中的一个,已经在内存中)?

更多信息: 我遇到的大多数问题都发生在CreateInstance周围,因为ClientContext在公共接口程序集X中,所以当我从路径A创建一个时,我的对话框上的构造函数似乎期待路径B中的构造函数。然后结束一个“未找到类型'ExternalTestForms.WindowDemo1'的构造函数。”错误。 (即使在路径A和路径B中使用完全相同的[签名和版本化]程序集,仍会发生此错误。)

我认为这涵盖了我用来加载程序集并使用界面创建自定义窗口的代码。

        public IExternalForm ShowExternalWindow(string filename, string classname, string parameters, string formIdentity)
        {
            if (File.Exists(filename))
            {
                ClientContext context = GetCurrentClientContext(parameters, formIdentity);

                object dialog = null;

                AppDomain currentDomain = AppDomain.CurrentDomain;
                currentDomain.AssemblyResolve += this.CurrentDomain_AssemblyResolve;

                this.basePath = Path.GetDirectoryName(filename);
                Assembly externalAssembly = Assembly.LoadFile(filename);

                try
                {
                    // The Window must must have a ClientContext defined in the constructor.
                    dialog = externalAssembly.CreateInstance(classname, false, BindingFlags.CreateInstance, null, new object[] { context }, context.Desktop.Culture, null);
                }
                catch (Exception ex)
                {
                    // MessageBox "Could not launch the Window"
                    // LogTraceException
                }

                if (dialog != null && dialog is IExternalForm && dialog is System.Windows.Window)
                {
                    System.Windows.Window window = (System.Windows.Window)dialog;
...
...
...
                }
...
            }
        }


        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string filename = args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";

            // Seek out the specified assembly in the current Application path first.
            string assemblyPath = Path.Combine(Application.StartupPath, filename);

            if (!File.Exists(assemblyPath))
            {
                assemblyPath = Path.Combine(this.basePath, filename);
            }

            if (File.Exists(assemblyPath))
            {
                // Load the assembly from the specified path.
                Assembly myAssembly = Assembly.LoadFrom(assemblyPath);

                // Return the loaded assembly.
                return myAssembly;
            }

            return null;
        }

1 个答案:

答案 0 :(得分:1)

要考虑的几个不同的低影响选项:

1)在应用程序启动时,仅将客户程序集复制到主文件夹中(我们要求客户程序集具有特定的命名约定以便加载,因此我们很容易实现)。

2)在应用程序启动时,删除客户目录中的标准DLL的任何副本以防止冲突。