首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

【200分,不够再加】如果利用配置文件指定程序集的位置,该如何解决

2012-01-22 
【200分,不够再加】如果利用配置文件指定程序集的位置之前就发过一个20分的贴子:http://topic.csdn.net/u/20

【200分,不够再加】如果利用配置文件指定程序集的位置
之前就发过一个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 code
<?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中的程序集,应该怎么办?

[解决办法]
不会 
Up
[解决办法]
我们使用的是

assembly = Assembly.LoadFrom( basePath + "AccessCodeGenerator\\SnakeEyes\\Fulfilment.AccessCodes.SnakeEyes.dll" );
generator= (IGenerator) assembly.CreateInstance( "Pongrass.PES.Fulfilment.AccessCodeGeneratorSnakeEyes" );

没有问题
[解决办法]
关注
[解决办法]
一篇文章http://blogs.msdn.com/junfeng/archive/2004/11/16/258081.aspx
我自己也正在试验如何使用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/

[解决办法]
下面的方法楼主可以试试
不过可能不是你想要的
因为这种指定路径的方法必须是处于主程序所以文件夹的子文件夹
[code=C#]
在配置文件中增加一节,如下

<configuration>
<runtime>
<assemblyBinding xmlns= "urn:schemas-microsoft-com:asm.v1 ">
<probing privatePath= "bin;bin2\subbin;bin3 "/>


</assemblyBinding>
</runtime>
</configuration>

可以在MSDN中索引 <probing>
[/code]
[解决办法]
不是同一路径,exe路径是

D:\test prj\vs2008\TestCodeBase\TestCodeBase\bin\Debug\TestCodeBase.exe
[解决办法]
顶~~~~~
[解决办法]
貌似publicKeyToken不能为null
[解决办法]
据 http://book.csdn.net/bookfiles/650/10065020609.shtml 说
从上面可以看到,<codeBase>元素内嵌在<assemblyIdentity>元素中。<assemblyIdentity>元素使用name特性和publicKeyToken特性定义友好名称和对应的publicKeyToken的值。<codeBase>元素则指定需要加载的程序集的版本和位置(通过href属性)。现在,如果只把GAC中的CarLibrary.dll的2.0.0.0版本删除,则客户端程序仍然可以正常运行,因为CLR在C:\MyAsms下能够找到被请求的程序集。

但是如果把MyAsms目录删除,则客户程序将会运行失败。这是因为<codeBase>元素的设置优先于GAC。

探讨
还有这个问题没解决:

另外,请问配置文件的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中的程序集,应该怎么办?



[解决办法]
可以手动用LoadLibrary跳过GAC
参考http://msdn.microsoft.com/en-us/library/yx7xezcf(VS.85).aspx
[解决办法]
经过测试GAC优先级高于CodeBase.
[解决办法]
很奇怪,我测试结果和sdfkfkd说的正好相反,
我测试的方法:
前提条件:
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



[解决办法]
估计除了反射没啥方法了吧。

好像同路径的的dll优先级都小于GAC
[解决办法]
关于这一点,我没有测试
下面是引用MSDN中关于<codebase>的帮助,可以索引中键入以上关键字
不过MSDN中并没有指明<codebase>和GAC的优选级问题
应该以具体测试为准吧


对于大多数 .NET Framework 应用程序而言,您可以在以下位置找到构成该应用程序的程序集,这些位置包括:该应用程序的目录中,该应用程序目录的子目录中,或全局程序集缓存中(如果该程序集是共享的话)。可以通过在配置文件中使用 <codeBase> 元素 重写公共语言运行库查找某一程序集的位置。如果该程序集没有强名称,则使用 <codeBase> 元素 指定的位置将被限制在应用程序目录或子目录中。如果程序集具有强名称,则 <codeBase> 元素 能够指定计算机或网络上的任意位置。

这一点验证了程序集必须使用强名称。

探讨
很奇怪,我测试结果和sdfkfkd说的正好相反,
我测试的方法:
前提条件:
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




[解决办法]
如果程序集有强名称,在首先在全局程序集缓(GAC)中查找程序集。
如果程序集的强名称没有正确指定或GAC中找不到,那么通过配置文件中的<codebase>元素指定的URL来查找

[解决办法]
学习了
[解决办法]
那这问题不就产生一个死结吗
楼主还是换程序集名称吧

探讨
引用:
估计除了反射没啥方法了吧。

好像同路径的的dll优先级都小于GAC


你反射也不行,因为LoadFrom方法中,如果所加载的程序集已加载,会返回现有程序集,而不会去加载

换句话说,GAC中已有System.Windows.Forms.dll,你LoadFrom("D:\\System.Windows.Forms.dll"),它并不去加载D盘下的DLL,而只是返回GAC中的DLL

[解决办法]
太高深了,菜鸟学习
[解决办法]
那你不是犟吗,用NJ话说就是甩,
它都制定好规则了,你还要反其道而行之

探讨
引用:
那这问题不就产生一个死结吗
楼主还是换程序集名称吧

引用:
引用:
估计除了反射没啥方法了吧。

好像同路径的的dll优先级都小于GAC


你反射也不行,因为LoadFrom方法中,如果所加载的程序集已加载,会返回现有程序集,而不会去加载

换句话说,GAC中已有System.Windows.Forms.dll,你LoadFrom("D:\\System.Windows.Forms.dll"),它并不去加载D盘下的DLL,而只是返回GAC中的DLL




“重名”是“刻意”而为之,还改什么名?要的就是这个效果

[解决办法]
那应该截获系统重绘消息或者继承之类的吧
你这样做貌似很难
不管怎样,楼主要是问题解决了,贴一下方法啊

探讨
引用:
那你不是犟吗,用NJ话说就是甩,
它都制定好规则了,你还要反其道而行之


这样的需求很正常吧?!

假如我想给WinForm程序换肤,但是我不能修改源代码,不能破坏用户的GAC,于是我可以给用户提供一个
System.Windows.Forms.dll(publickey跟GAC中的一样)和.config文件,这样用户不需要做任何操作,就可以使用我定义的皮肤,而不是系统默认的

类似的需求太多了

[解决办法]
好东西~~ 太帅了~~学习好多东西~~
[解决办法]
探讨
引用:
估计除了反射没啥方法了吧。

好像同路径的的dll优先级都小于GAC


你反射也不行,因为LoadFrom方法中,如果所加载的程序集已加载,会返回现有程序集,而不会去加载

换句话说,GAC中已有System.Windows.Forms.dll,你LoadFrom("D:\\System.Windows.Forms.dll"),它并不去加载D盘下的DLL,而只是返回GAC中的DLL

[解决办法]
探讨
引用:
那你不是犟吗,用NJ话说就是甩,
它都制定好规则了,你还要反其道而行之


这样的需求很正常吧?!

假如我想给WinForm程序换肤,但是我不能修改源代码,不能破坏用户的GAC,于是我可以给用户提供一个
System.Windows.Forms.dll(publickey跟GAC中的一样)和.config文件,这样用户不需要做任何操作,就可以使用我定义的皮肤,而不是系统默认的

类似的需求太多了

[解决办法]
探讨
引用:
那你不是犟吗,用NJ话说就是甩,
它都制定好规则了,你还要反其道而行之


这样的需求很正常吧?!

假如我想给WinForm程序换肤,但是我不能修改源代码,不能破坏用户的GAC,于是我可以给用户提供一个
System.Windows.Forms.dll(publickey跟GAC中的一样)和.config文件,这样用户不需要做任何操作,就可以使用我定义的皮肤,而不是系统默认的

类似的需求太多了

[解决办法]
好好想想啊

[解决办法]
你用动态编译算了
把dll内容base64编码后写入配置文件或资源,不需要dll都行了
[解决办法]
publickey跟GAC中的一样这条做不到,微软是不会把自己的private key给你的。
[解决办法]
不懂学习一下
[解决办法]
mark
------解决方案--------------------


探讨
引用:
2.强命工具太多了,产生一个PublicKey相同的程序集太容易

[解决办法]
我就奇怪了,楼主怎么不用这种方法:
C# code
Assembly.LoadFile(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.dll")
[解决办法]
。net 的吗 给你个方法 动态加载调用托管dll
C# code
 /// <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
[解决办法]
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="D:\my\"/>
</assemblyBinding>
</runtime>

楼主试一下吧!
[解决办法]

[解决办法]
有点高深...
[解决办法]
不懂。。
[解决办法]
路过。up
[解决办法]
引用49楼的就行了
[解决办法]
... ...
[解决办法]
的确是深了点,学习........
[解决办法]
uP
[解决办法]
参考学习中
[解决办法]
xuexixuexi
[解决办法]
顶~
[解决办法]
o 学习咯~
[解决办法]
48楼 不错~ dll的确在这个里面也有
------解决方案--------------------


学习
[解决办法]
学习
[解决办法]
关注
[解决办法]

探讨
不会
Up

[解决办法]
学习!
[解决办法]
mark up.
[解决办法]
C# code
我也这样用assembly = Assembly.LoadFrom( basePath + "AccessCodeGenerator\\SnakeEyes\\Fulfilment.AccessCodes.SnakeEyes.dll" ); generator= (IGenerator) assembly.CreateInstance( "Pongrass.PES.Fulfilment.AccessCodeGeneratorSnakeEyes" ); 没有问题
[解决办法]
sharp_future你的图像不错!
[解决办法]
顶起
[解决办法]
在应用程序配置文件中输入以下 XML: 

复制代码 
<?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> 元素中不能指定版本范围。


[解决办法]
学习下
[解决办法]
面的示例说明如何指定程序集的位置。 

复制代码 

[解决办法]
学习之
[解决办法]
学习中
[解决办法]

[解决办法]
ert yrtytr
[解决办法]
gdf g r r
[解决办法]

[解决办法]
.
[解决办法]
帮 顶
[解决办法]
帮顶 学习 刚学习 C++
------解决方案--------------------


恭喜恭喜啊,分数提高吸引这么多人过来啊

[解决办法]
马克
[解决办法]
关注中
[解决办法]
关注!
[解决办法]
不能给你解决问题但是留下足迹以示支持
[解决办法]
标题错了吧?我也不知道。等答案....
[解决办法]
关注
[解决办法]
我是个门外汉!但谁能帮我找回QQ啊 这是我现在的624316753
谢谢
[解决办法]
頂,學習
[解决办法]
不会,等答案……
[解决办法]
關注..
[解决办法]
加油啊!!!
有问题才有进步!!!!
[解决办法]
不懂,但是先学习。。。
[解决办法]

C# code
//试试下面的//路径也可以写在INI文件或者XML文件中[System.Runtime.InteropServices.DllImport("读取配置文件中的路径", EntryPoint = "方法", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = false)]        static extern int 方法(); 

热点排行