方法1:利用AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);事件
转自:http://blog.youkuaiyun.com/dyllove98/article/details/9391325
我们的应用程序部署的时候,目录结构一般不会只有运行程序的目录这一个,我们可能在运行目录下建子目录,也可能使用System32目录,也可能使用其它第三方的程序集。.Net程序集
首先会在GAC中搜索相应的版本,如果未找到则会应用程序配置文件中找(如果配置),最后到应用程序所在的路径搜索。
如何可以将程序集部署的运行目录的子目录, 在app.config添加以下配置,其中probing的privatePath就是配置当前程序搜索的子目录
<configuration> ... ... <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="Plugins;Libs"/> </assemblyBinding> </runtime> </configuration>
当然我们也可以更详细的配置,不过似乎一般这么用的很少,这里可以指定程序集名称、公钥、文化,版本重定向等等信息
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="myAssembly" publicKeyToken="32ab4ba45e0a69a1" culture="neutral" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/> <codeBase version="2.0.0.0" href="http://www.litwareinc.com/myAssembly.dll"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
Msdn地址:http://msdn.microsoft.com/zh-cn/library/twy1dw1e(v=vs.80).aspx
如何加载非运行目录的程序集?也许有的人会想到反射,的确对应单独的一个程序集我们可以直接调用使用 Assembly.LoadFile(@"XXX.dll");加载,再使用反射对其中的方法属性进行调
用,但是如果这个程序集同时引用了其它的,非应用程序运行目录下的程序集,这时就会出错,这个问题该如何解决呢?
我曾尝试用 Assembly.LoadFile(@"XXX.dll");加载那些依赖的程序集,但是没有成功,调用继续出错。使用 AppDomain.CurrentDomain.GetAssemblies()查看,所有的应用程序集都已经加载到了当前应用程序域,但是为什么还是找不到依赖的哪些程序集呢?后来查询未果,希望有高人能回答下。
最后使用了AppDomain.CurrentDomain.AssemblyResolve事件解决了以上问题,希望遇到同样问题的同学们少走弯路,在程序初始化的时候添加监听事件
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
在监听的事件中遇到要加载额外的dll的时候,返回 Assembly.LoadFrom(strTempAssmbPath)即可
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { var strTempAssmbPath = ""; if ("qrcsharp" == args.Name.Substring(0, args.Name.IndexOf(","))) { var systemFolder = Environment.GetFolderPath(Environment.SpecialFolder.System); strTempAssmbPath = System.IO.Path.Combine(systemFolder, "qrcsharp.dll"); } return string.IsNullOrWhiteSpace(strTempAssmbPath) ? null : Assembly.LoadFrom(strTempAssmbPath); }
方法2:签名+环境变量
转自:http://www.cnblogs.com/yunhuasheng/archive/2008/03/12/1102542.html
http://bbs.youkuaiyun.com/topics/391849269
http://www.doc88.com/p-23574117789.html
.net 注册引用的dll
正好现在做的这个项目就是这种情况,看了一下网上的资料也不多,于是将自己的解决方法share一下,有什么不好的地方,恳请指正。
大家都知道,在.Net中,如果你试图将一个dll写入到GAC中,那么除了你的dll项目要使用strong name以外,你的项目中用到的其它的控件或dll都需要有strong name,否则,当你注册你的dll时,会提示缺少dependency。这一点让人很烦,但应该有它的好处,利于版本控制。既然是这样,我们只有将引用到的控件或dll都加上strong name,并写入到GAC中,这样在注册你的dll时,就会到GAC中去找它所用到的控件或dll了。那么,如何做呢?大致分两步:
1、给需要引用的控件或dll加strong name
这是必须要做的,否则你无法把他们写到GAC中。.Net的SDK提供一个给程序集生成强名的工具,其实不只是生成,还有管理及签名的验证等,只是根据不同的option来的。详细说明请参考MSDN。下面是通过sn创建一个key pair,存储在keyfile.snk中:
这样就生成了一个密钥对。如果你的项目中没有引用其它的不带强名的控件或dll的话,只是想把自己的dll写入GAC,那么在你项目的AssemblyInfo.cs中,把AssemblyKeyFile加上,就是你刚才生成的keyfile.snk文件。
这里的路径是指编译后项目输出的相对路径,所以,如果这里写成这样的话(当然你也可以修改),就应该把刚才生成的keyfile.snk拷贝到项目的跟目录下,以确保在编译的时候能找到snk文件。这样,编译后的dll就可以写到GAC中了:
如果你的项目中引用了其它的不带有强名的控件或dll的话,就需要再做下一步。
2、给不带有强名的控件或dll加上强名
这里要用到两个工具,也是.Net自带的,tlbimp和aximp。tlbimp是将COM类型库中的类型定义转换为CLR程序集的等效定义,aximp是将COM类型库中的类型定义转换为windows窗体控件,详细说明请参考MSDN。
假设你要给tom.dll和MSFlxGrd.ocx加上强名:
aximp MSFlxGrd.ocx keyfile:MSFlxGrd.ocx.snk AxMSFlxGrd.ocx.snk
这里,tom.dll.snk、MSFLlxGrd.ocx.snk和AxMsFlxGrd.ocx.snk是根据第一步产生的,每一个dll都要对应一个snk。tom.dll为转换过的dll的名字,没有什么其它含义。另外需要说明的是MSFlxGrd.ocx会产生两个dll,分别是MSFlexGridLib.dll和AxMSFlexGridLib.dll。个人理解为在窗体初始化时会产生一个AxMSFlexGridLib,不知谁有更好的解释?
这样就把tom.dll和MSFlxGrd.ocx控件加上了强名称并转换为相应的dll了,再把它们写入到GAC中:
gacutil -i MSFlexGridLib.dll
gacutil -i AxMSFlexGridLib.dll
剩下的工作就是将它们重新引用到你的项目中,重新编译,这样生成的dll在注册时就不需要任何dependency了,因为它们已经在GAC中了,打开c:\winnt\assembly即可看到。
如果要将它们从GAC中删除,则:
gacutil -u MSFlexGrid
gacutil -u AxMSFlexGrid
tom、MSFlexGrid和AxMSFlexGrid为GAC中的名字,这里不需要加任何路径