之前就发过一个20分的贴子:http://topic.csdn.net/u/20091127/21/a67465c7-44ce-4e5f-95a7-42d98ba4e4d9.html结果没几个人关注,所以现在提高到10倍,发一个200分的贴子,希望有人能解决.问题描述如下:首先写一个Library.dll:
class Library
{
}生成一个Library.dll文件,置于 d:\my\Library.dll然后写一个Demo.exe,添加对Library.dll的引用,添加一个配置文件App.config(编译之后,会在exe目录产生一个demo.exe.config文件),并编写如下代码:Console.WriteLine(typeof(Library).Assembly.Location);使其输出为d:\my\Library.dll
运行时,demo.exe和demo.exe.config文件在同一目录下,而dll被我移走了,跟exe的路径无关,而是在前面提到的位置d:\my\Library.dll请问,配置文件应该怎么写,才能正常运行,并使Console.WriteLine(typeof(Library).Assembly.Location)输出的路径为d:\my\Library?我自己在网上查到的方法是这样的,但是不对:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity Name="Library" Culture="neutral" PublicKeyToken="null" />
<codeBase version="1.0.0.0" href="FILE://D:/my/Library.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>即使给Library产生一个PublicKeyToken,并在配置文件中指明,也是没用的麻烦给出配置文件的全部内容另外,请问配置文件的codeBase路径和GAC,哪个的优先级高?假如我把GAC中的System.Windows.Forms.dll复制到d:\my\System.Windows.Forms.dll,要使程序中的:
Console.WriteLine(typeof(Form).Assembly.Location)输出为d:\my\System.Windows.Forms.dll,也就是让程序优先使用我请明的程序级,而不是优先使用GAC中的程序集,应该怎么办?
class Library
{
}生成一个Library.dll文件,置于 d:\my\Library.dll然后写一个Demo.exe,添加对Library.dll的引用,添加一个配置文件App.config(编译之后,会在exe目录产生一个demo.exe.config文件),并编写如下代码:Console.WriteLine(typeof(Library).Assembly.Location);使其输出为d:\my\Library.dll
运行时,demo.exe和demo.exe.config文件在同一目录下,而dll被我移走了,跟exe的路径无关,而是在前面提到的位置d:\my\Library.dll请问,配置文件应该怎么写,才能正常运行,并使Console.WriteLine(typeof(Library).Assembly.Location)输出的路径为d:\my\Library?我自己在网上查到的方法是这样的,但是不对:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity Name="Library" Culture="neutral" PublicKeyToken="null" />
<codeBase version="1.0.0.0" href="FILE://D:/my/Library.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>即使给Library产生一个PublicKeyToken,并在配置文件中指明,也是没用的麻烦给出配置文件的全部内容另外,请问配置文件的codeBase路径和GAC,哪个的优先级高?假如我把GAC中的System.Windows.Forms.dll复制到d:\my\System.Windows.Forms.dll,要使程序中的:
Console.WriteLine(typeof(Form).Assembly.Location)输出为d:\my\System.Windows.Forms.dll,也就是让程序优先使用我请明的程序级,而不是优先使用GAC中的程序集,应该怎么办?
generator= (IGenerator) assembly.CreateInstance( "Pongrass.PES.Fulfilment.AccessCodeGeneratorSnakeEyes" );没有问题
我自己也正在试验如何使用CodeBase
看起来publickey是很重要的。下面的配置是ok的。
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="ClassLibrary1" publicKeyToken="2af6181c6a13eff6" culture="neutral"/>
<codeBase version="1.0.0.0" href="D:\test prj\vs2008\TestCodeBase\ClassLibrary1\bin\Debug\ClassLibrary1.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>如何为dll生成publickey呢,很简单。
dll项目属性
Signing页
选中 Sign the assembly
可以新建一个密钥文件,随便输入一个名字,不用加密。至于如何取得assembly的public key.
我是使用的reflector
http://www.red-gate.com/products/reflector/
不过可能不是你想要的
因为这种指定路径的方法必须是处于主程序所以文件夹的子文件夹在配置文件中增加一节,如下<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>可以在MSDN中索引<probing>
为什么不选用"毫不相关"的路径呢?你这两个路径有一定关联,即使成功了,也不是很有说服力另外,麻烦你能否把工程发到我邮箱[email protected]
http://book.csdn.net/bookfiles/650/10065020609.shtml
找到原因了,原来是
<assemblyIdentity name="ClassLibrary1" publicKeyToken="2af6181c6a13eff6" culture="neutral"/>中的name和publicKeyToken首字母必须小写,而culture大小写无所谓这也太............VS2008里配置文件没有智能感知吗?
Console.WriteLine(typeof(Form).Assembly.Location)输出为d:\my\System.Windows.Forms.dll,也就是让程序优先使用我请明的程序级,而不是优先使用GAC中的程序集,应该怎么办?
从上面可以看到,<codeBase>元素内嵌在<assemblyIdentity>元素中。<assemblyIdentity>元素使用name特性和publicKeyToken特性定义友好名称和对应的publicKeyToken的值。<codeBase>元素则指定需要加载的程序集的版本和位置(通过href属性)。现在,如果只把GAC中的CarLibrary.dll的2.0.0.0版本删除,则客户端程序仍然可以正常运行,因为CLR在C:\MyAsms下能够找到被请求的程序集。但是如果把MyAsms目录删除,则客户程序将会运行失败。这是因为<codeBase>元素的设置优先于GAC。
参考http://msdn.microsoft.com/en-us/library/yx7xezcf(VS.85).aspx
我测试的方法:
前提条件:
1. 编译ClassLibrary1
函数为
public int Add(int i, int j)
{
return i + j;
}
放ClassLibrary1.dll进GAC
2. 修改函数为
public int Add(int i, int j)
{
return i + j + 1;
}
放ClassLibrary1.dll到codebase指定的路径3. exe调用函数
Class1 cls = new Class1();
MessageBox.Show(cls.Add(1, 2).ToString());测试case:
1. 不设置Codebase.
函数调用返回3
2. 设置CodeBase
函数依然返回3
3. 设置Codebase,并将GAC中的ClassLibrary1.dll删除
函数返回4
typeof(Form).Assembly.Location在dll的路径就知道是GAC,还是codebase了现在的问题是,如果GAC优先于CodeBase,那有什么办法使得程序使用指定路径的程序集(反射就不用说了,那个人人都懂),而非GAC?
下面是引用MSDN中关于<codebase>的帮助,可以索引中键入以上关键字
不过MSDN中并没有指明<codebase>和GAC的优选级问题
应该以具体测试为准吧
对于大多数 .NET Framework 应用程序而言,您可以在以下位置找到构成该应用程序的程序集,这些位置包括:该应用程序的目录中,该应用程序目录的子目录中,或全局程序集缓存中(如果该程序集是共享的话)。可以通过在配置文件中使用 <codeBase> 元素 重写公共语言运行库查找某一程序集的位置。如果该程序集没有强名称,则使用 <codeBase> 元素 指定的位置将被限制在应用程序目录或子目录中。如果程序集具有强名称,则 <codeBase> 元素 能够指定计算机或网络上的任意位置。这一点验证了程序集必须使用强名称。
如果程序集的强名称没有正确指定或GAC中找不到,那么通过配置文件中的<codebase>元素指定的URL来查找
你反射也不行,因为LoadFrom方法中,如果所加载的程序集已加载,会返回现有程序集,而不会去加载换句话说,GAC中已有System.Windows.Forms.dll,你LoadFrom("D:\\System.Windows.Forms.dll"),它并不去加载D盘下的DLL,而只是返回GAC中的DLL
这样的需求很正常吧?!假如我想给WinForm程序换肤,但是我不能修改源代码,不能破坏用户的GAC,于是我可以给用户提供一个
System.Windows.Forms.dll(publickey跟GAC中的一样)和.config文件,这样用户不需要做任何操作,就可以使用我定义的皮肤,而不是系统默认的类似的需求太多了
把dll内容base64编码后写入配置文件或资源,不需要dll都行了
1. 我把GAC的程序集复制出来总可以吧?2.强命工具太多了,产生一个PublicKey相同的程序集太容易
/// <summary>
/// 动态调用托管dll function showform:boolean;stdcall;
/// </summary>
/// <param name="lpFileName">dll文件名</param>
/// <param name="Namespace">命名空间</param>
/// <param name="ClassName">类名</param>
/// <param name="lpProcName">方法名</param>
/// <param name="ObjArray_Parameter">参数</param>
/// <returns></returns>
public static object Invoke(string lpFileName, string Namespace, string ClassName, string lpProcName, object[] ObjArray_Parameter)
{ try
{ // 载入程序集 Assembly MyAssembly = Assembly.LoadFrom(lpFileName); Type[] type = MyAssembly.GetTypes(); foreach (Type t in type)
{// 查找要调用的命名空间及类 if (t.Namespace == Namespace && t.Name == ClassName)
{// 查找要调用的方法并进行调用 MethodInfo m = t.GetMethod(lpProcName); if (m != null)
{ object o = Activator.CreateInstance(t); return m.Invoke(o, ObjArray_Parameter); } else MessageBox.Show(" 装载出错 !"); }
} }//try catch (System.NullReferenceException e)
{ MessageBox.Show(e.Message); }//catch return (object)0; }// Invoke
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="D:\my\"/>
</assemblyBinding>
</runtime>楼主试一下吧!
我也这样用assembly = Assembly.LoadFrom( basePath + "AccessCodeGenerator\\SnakeEyes\\Fulfilment.AccessCodes.SnakeEyes.dll" );
generator= (IGenerator) assembly.CreateInstance( "Pongrass.PES.Fulfilment.AccessCodeGeneratorSnakeEyes" ); 没有问题
<?xml version ="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v1.1.4322" />
</startup>
</configuration>
只有在计算机配置文件或也重定向程序集版本的发行者策略文件中,才可以使用 <codeBase> 元素。在运行库确定要使用哪一程序集版本时,它应用确定版本的文件中的基本代码设置。如果未指出基本代码,那么运行库就以通常的方法探测程序集。有关详细信息,请参见运行库如何定位程序集。下面的示例说明如何指定程序集的位置。复制代码
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<codeBase version="2.0.0.0"
href="http://www.litwareinc.com/myAssembly.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
对于所有具有强名称的程序集,要求 version 属性,但对于不具有强名称的程序集应省略。<codeBase> 元素要求 href 属性。在 <codeBase> 元素中不能指定版本范围。
//试试下面的
//路径也可以写在INI文件或者XML文件中
[System.Runtime.InteropServices.DllImport("读取配置文件中的路径", EntryPoint = "方法", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = false)]
static extern int 方法();