.NET中的DLL Hell及其解决办法

假设这样一种场景,某公司推出了两款软件(分别叫A1和A2),这两款软件均引用了同一个公共的程序集(Common.dll),同时A1和A2均使用到了Common.dll中的GetMessage1()方法,现在用户将这两款软件分别安装到自己的系统中。此时公共的程序集被拷贝到用户的某个路径下,这样它可以被两个软件同时引用。过了一段时间后,该公司对软件A2进行升级,升级过程中需要修改Common.dll中的GetMessage1()的函数名,将其更名为GetMessage2()。当用户下载A2软件进行安装时,Common.dll会同时被下载安装到之前的公用文件夹下并将原来版本的Common.dll覆盖。现在问题来了,A2在用户那里可以正常运行,但A1却不行。因为Common.dll中的GetMessage1()已经不存在,所以在运行A1的时候会抛出异常。

下面用代码模拟上面出现的情况。

一开始我们新建一个Common.dll的程序集:

    public static class Tool
    {
        public static string GetMessage1()
        {
            return "Hello world!";
        }
    }

再新建一个名为T1的Console程序,我们将刚才生成Common.dll拷贝到A1的bin目录,并且让A1添加对其引用:

namespace A1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Common.Tool.GetMessage1());
        }
    }
}

编译改程序后将A1.exe已经Commo.dll拷贝到另一个单独的文件夹(MyFolder)中,此时A1可以正常运行。

然后,我们按照同样的方式新建一个A2的Console程序,同样添加对Common.dll的引用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace A2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Common.Tool.GetMessage1());
            Console.ReadLine();
        }
    }
}

此时,我们将A2和Common.dll拷贝到MyFolder中。此时在MyFolder下分别运行A1和A2,发现他们均能正常运行。

现在我们要模拟软件A2升级。我们将刚才的Commo.dll程序代码中的GetMessage1()更名为GetMessage2(),同时将A2中的代码改为调用GetMessage2()函数。分别编译Common.dll和A2项目。

Common.dll代码:

namespace Common
{
    public static class Tool
    {
        public static string GetMessage2()
        {
            return "Hello world!";
        }
    }
}

A2代码改为:

namespace A2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Common.Tool.GetMessage2());
            Console.ReadLine();
        }
    }
}

分别将Common和A2编译后将Common.dll和A2.exe拷贝/覆盖到MyFolder中。此时在MyFolder下我们会发现A2能正常运行,A1却抛出异常:

原因很简单,因为在对A2升级的时候,GetMessage1已经被改名为GetMessage2,那么A1运行时当然会抛出异常。

那么如何解决这个问题呢?答案是:我们可以对Common进行版本控制,同时对其强类型命名,然后将Common部署到GAC中。每次对Common做改动/升级,我们对增加一个版本号,不同的软件引用不同的版本。虽然Common的名字还是没变,但版本号却在每次发布的时候有变化,对于GAC来说他们就是不同的程序集了。

现在我们回到最开始的状态,此时Common中的函数名仍然为GetMessage1,我们对该程序集进行强类型签名。步骤是:

  1)右键程序集选择属性(properties),然后选择签名(Signing)

  2)勾选签名这个程序集(Sign the Assembly),并在下拉列表中选择新建

  3)在弹出的框中给key起一个名字,在单击ok

这样我们就给Common.dll签上了强类型名称,接下来需要将Common.dll部署到GAC中。我们可以运用VS提供的命令行工具然后用gactuil -i命令将其部署到GAC。

然后按照同样的步骤,让A1和A2均添加对Common.dll的引用,代码和上文中一开始的地方一模一样。

将A1和A2拷贝到MyFolder中,此时因为A1和A2添加了Common.dll的引用,而Common.dll已经部署到GAC中,所以不需要将Common.dll拷贝到MyFolder中,因为A1和A2会从GAC中找到该程序集。此时A1和A2完全能正常运行。

现在我们要做的是,模拟A2升级,并且对Common.dll进行修改。

还是将Common中的GetMessage1改为GetMessage2。然后打开Common的AssemblyInfo,将[assembly: AssemblyVersion("1.0.0.0")]改为[assembly: AssemblyVersion("2.0.0.0")]。这样做的目的是让改Common变为2.0,区别之前的版本。同样将该Common部署到GAC中。

同样在A2中添加对新版本的Common的引用,将A2的代码更新为使用GetMessage2版本。

namespace A2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Common.Tool.GetMessage2());
            Console.ReadLine();
        }
    }
}

然后将A2.exe拷贝到MyFolder下。现在在MyFloder下A1.exe引用的是GetMessage1而A2.exe使用的是GetMessage2,但她们却引用的是同名的Common.dll,只是A1和A2引用的不同版本的Common.dll。这是A1和A2均可正常运行。

而在GAC中,我们可以发现有两个版本的Common.dll

时间: 2024-11-05 12:43:24

.NET中的DLL Hell及其解决办法的相关文章

win8和win7下解决php5.3和5.4、5.5等不能加载php_curl.dll的终极解决办法 收藏

win8和win7下解决php5.3和5.4.5.5等不能加载php_curl.dll的终极解决办法 收藏2015年01月11日 最近分别在WIN7和Windows8 上分别安装php 高版本!都遇到了这个问题! 一.win7系统32位, apache2.2, php5.2升级到5.4. 这个比较容易: 1. phpinfo发现没有加载curl; 2. 在php.ini中设置extension_dir 指向e:\php5.4\ext; 部分php扩展加载了, 但curl仍不行. 3. 设置win

linux中无 conio.h的解决办法

conio.h不是C标准库中的头文件,在ISO和POSIX标准中均没有定义.conio是Console Input/Output(控制台输入输出)的简写,其中定义了通过控制台进行数据输入和数据输出的函数,主要是一些用户通过按键盘产生的对应操作,比如getch()函数等等.大部分DOS,Windows,Phar Lap,DOSX,OS/2等平台上的C编译器提供此文件,UNIX和Linux平台的C编译器本身通常不包含此头文件,但已经有其兼容包,可参考: http://conio.sourceforg

GDI+中发生一般性错误的解决办法(转载)

今天在开发.net引用程序中,需要System.Drawing.Image.Save 创建图片,debug的时候程序一切正常,可是发布到IIS后缺提示出现"GDI+中发生一般性错误"的异常.于是开始"摆渡",并寻找到了解决办法:赋予 NETWORK SERVICE 帐户以写权限. 以下为晚上寻找到的资料: 在开发.NET应用中,使用 System.Drawing.Image.Save 方法而导致"GDI+ 中发生一般性错误"的发生,通常有以下三种

MySQL集群架构以及本人配置过程中出现的问题及解决办法

首先说下MySQL的优缺点 优点 解决单点故障 自动实现数据冗余 缺点就是维护起来太麻烦. 集群的条件就是所有的机器上都要安装MySQL的集群软件,我安装的是MySQL-Cluster-gpl-7.3.5-1.el6.x86_64.rpm的rpm包,不是源码包安装.如果系统里面安装了mysql-server等数据库服务软件的要自行写在掉即可. MySQL集群中有三种角色,下面是三种角色以及其的作用 角色 数据节点:ndbd节点 存储在表里的数据(表中的记录) SQL节点:不存储数据,供用户访问和

新建解决方案 在解决方案中添加项目中,解决方案消失的解决办法

新建空白解决方案的步骤:文件--新建项目--其他项目类型--Visual Studio 解决方案 这样就建立出了一个空白解决方案. 然后在资源管理器中可以添加项目,但是添加项目的时候会发现,解决方案消失了,解决办法  工具--选项--项目和解决方案(如果看不到这个,在下方有一个显示所有设置打勾),然后右边有一个 总是显示解决方案.勾上,解决方案就出现了 记录一下. 新建解决方案 在解决方案中添加项目中,解决方案消失的解决办法,布布扣,bubuko.com

基于H.264协议的视频传输系统中遇到的问题以及解决办法

问题1.视频压缩解码模块在运用的时候出现错误:解码器再解码第二帧视频图片的时候出现异常 client: ../../decoder/T264dec.c:594:T264dec_decode_nal: Assertion `0' failed. Aborted 对于该问题的分析及解决过程为: 1.  修改数据类型,所有缓存区改为unsigned char类型(原来统一为char 类型),但是还是遇到一样的异常错误,问题没有解决. 2.  查看缓存区具体内容是否与服务器端压缩的数据是一致的的,对照数

MyEclipse迁移过程中Tomcat版本不一致的解决办法

MyEclipse迁移过程中Tomcat版本不一致的解决办法 下面就是在MyEclipse2013迁移被Tomcat6.0X绑定的项目迁移到MyEclipse2014 Tomcat8.0X,报如下problems那栏的错误: 看见这个迁移过程中Tomcat版本不一致的错误,知道了就比较简单,不知道的时候就比较难了,解决办法如下: 1.查找到MyEclipse里面的菜单栏里面的MyEclipse 2.点击MyEclipse里面的Migrate Projects选项后,就出现如下图: 3.点击上图里

关于Excel文件导入到Sqlserver2008中出现截断错误的解决办法

出现错误的可能原因: 1.数据库字段Varchar长度不够: 2.不能用Text类型: 3.数据中可能存在换行符: 4.数据项文本过长,超过4000: 5.前8行的最大长度不够大,后面有超过的. 解决办法: 1.修改Varchar长度为足够长: 2.替换掉换行符(可手工输入一个换行符,复制到替换文本框中,Office中可按住Alt键,从小键盘输入10,再松开Alt键): 3.第一行中记录设足够长,导入后再替换: 4.把Excel文件存为2007格式,可解决导入后很多数据项为NULL的问题: 5.

C#中WebClient中文乱码的解决办法

原文:C#中WebClient中文乱码的解决办法 第一次尝试: string question = textBox1.Text.ToString(); WebClient youdao = new WebClient(); youdao.Encoding = System.Text.Encoding.GetEncoding("GB2312"); Uri uri = new Uri("http://xxxxxxxxxxxxxx"); textBox1.Text =yo