CharlesChen's Technical Space

简单实用是我一直在软件开发追求的目标(I Focus on. Net technology, to make the greatest efforts to enjoy the best of life.)
Not the best, only better
  博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

    在目前的项目中使用到了Enterprise Library中的SQLCE程序集遇到了下面的问题,通过分析原因找到了解决方案,这里和朋友们分享。

     出错提示:程序集“Microsoft.Practices.EnterpriseLibrary.Data.SqlCe, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”所使用的“System.Data.SqlServerCe, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91”版本高于所引用的程序集“System.Data.SqlServerCe, Version=3.5.1.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91”的版本。为什么会出现这个提示呢?

    分析原因:我使用的是EnterpriseLibrary 3.1用的Microsoft.Practices.EnterpriseLibary.Data.SqlCe的版本是3.1.0.0,而我使用System.Data.SqlServerCe.dll的版本是3.5.1.0.由于Microsoft.Practices.EnterpriseLibary.Data.SqlCe 3.1.0.0和System.Data.SqlServerCe.dll 9.0.242.0版本是绑定了的。(具有强名称的程序集)。所以我用System.Data.SqlServerCe 3.5.1.0版本会提示我不能通过!!

    思考

     1、EnterpriseLibrary 4.1使用的是Microsoft.Practices.EnterpriseLibrary.Data.SqlCe 4.1.0.0.所依赖的System.Data.SqlServerCe.dll是3.5.1.0,所以升级EnterpriseLibray的版本即可(3.1-->4.1).但是这个方法会引来一个问题:我使用Enterprise Library 4.1的话,会依赖于.net Framework 3.5。我不想依赖于.Net 3.5,所以我决定这个方案是不可取的。所以想到了第二个解决方案。

    2、System.Data.SqlServerCe 3.5.1.0是.net Compact Framework 3.5 sp1,而System.Data.SqlServerCe 9.0.242.0是.net Compact Framework3.5,换个思想,我引用System.Data.SqlServerCe 9.0.242.0这个Dll不就解决问题了吗?可如果这样的话,我用System.Dasta.SqlServerCe 9.0.242.0建立操作数据库的SQL CE版本和System.Data.SqlServer 3.5.1.0操作数据库的版本是不一样的,为了符合接口的一致性,所以使用System.Data.SqlServer 3.5.1.0这个Dll的版本是不能改变的。所以就只有另想办法。

    解决方案:

不能更改.net Framework的版本,不能更改System.Data.SqlServer 3.5.1.0(.net Compact Framework 3.5 sp1)的版本,能解决这个问题吗?高版本怎么不能兼容低版本呢?可以通过.net程序集的版本控制来实现:bindingRedirect元素.(将一个程序集的版本重定向另一个程序集的版本)

 

Configuration
<runtime>
    
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      
<dependentAssembly>
        
<assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845dcd8080cc91"/>
        
<bindingRedirect oldVersion="9.0.242.0" newVersion="3.5.1.0" />
      
</dependentAssembly>
    
</assemblyBinding>
 
</runtime>

 

 

当我遇到这个问题的时候,产生了这样一个想法,我这里也和朋友们分享一下:

    我们自己开发的程序集,如取名Charles2008.Framework Version=1.0.0.0  Culture=zh-cn PublicKeyToken=null,在一个应用程序中正常运行,然而一段时间后,我们对Charles2008.FrameWork进行了修改,并更新了版本号为Charles2008.Framework Version=2.0.0.0  Culture=zh-cn PublicKeyToken=null

我们是怎么升级的呢?直接替换了该dll,并没有配置BindingRedirect就能正常的运行。那为什么用System.Data.SqlServerCe这个dll就需要配置呢?

    答案是:System.Data.SqlServerCe.dll是强名称的程序集.而我自己写的Charles2008.Framework并没有对它进行强命令的签名,所有应用程序并没有和指定的程序集进行绑定,所以就不会出现问题。

 

补充一些关于StrongName的原理:

StrongName是一种.Net提供的身份识别机制。它基于一些加密算法,例如RSA等,对程序集进行实施签名。从而使得我们可以识别某个程序集的身份(该程序集是谁发布的)。其实,从本质上说,StrongName和证书机制(如X.509)的身份识别原理是相同的,区别是证书机制关系的事客户端能否证明自己具有一定的资格,而StrongName只是表示特定的身份,这个身份仅仅是针对某个程序集而言。

一、StrongName的原理:

StrongName---强名称,这个名称的含义是相对于WeekName(弱名称)而言的。(我们可以把没有嵌入公钥和使用私钥签名的程序集称之为弱名称(weak name)程序集。)

MSDN上程序集全名称的概念---FullName是由一个FullName字符串表示的:它的格式如下:"[程序集名称]   Version=[版本号]   Culture=[文化区域]   PublicKeyToken=[公钥标识]",如上面的"System.Data.SqlServerCe  Version=3.5.1.0 Culture=neutral   PublicKeyToken=89845dcd8080cc91",这些关于Name的信息中[程序集名称]、[ 版本号]、[文化区域]都是说明性的信息,他们与PublicKeyToken的区别是,前三个是可以任意伪造的。但是PublicKeyToken是不可以伪造的,是和特定程序集唯一绑定的。如果你想冒充原作者来发布一个恶意的程序集,你可以取名为System.Data.SqlServerCe,用3.5.1.0来生成版本号,文化区域设置为neutral,但是由于没有特定的密钥文件来给他的恶意程序集签名,所以他无法冒充原程序集的作者。

强名称程序集和弱名称程序集相比,有以下特点:

1、强名称程序集可保证唯一性。密钥对由发行者产生的,是唯一的。可保证程序集标识不会重复。

2、强名称程序集可防篡改。强名称的程序集使用私钥对自己进行了签名,在被加载时可检测是否被修改。

3、强名称程序集可实施版本策略。对于弱名称而言,引用它的程序不会关心它的版本,而对于强类型的程序集来说,引用它的程序会被绑定到特定版本的程序集上。如果新版本的强名称替换旧版本,会导致程序无法运行。(当然可以用配置文件对强名称程序集进行重定向)。

4、强名称程序集可以部署到GAC中。不同版本的相同程序集还可以同时存在于GAC中。

5、强名称程序集只能引用强名称的程序集。弱名称的程序集可以引用强名称程序集,也可以引用弱名称的程序集。但强名称的程序集只能引用强名称的程序集。

6、强名称的程序集支持并行执行。并行(side-by-side)执行是指程序同时引用多个版本的同名程序集,这样在运行时,会有多个版本的同名程序集被加载和同时。但通常都比较少。

 

二、命令

sn -k ***.snk---生成密钥文件.SN会将公钥/私钥对写入***.snk文件。请务必保证该文件不会落入不可信任的人手中。否则别人就可以冒充你来发布代码。

sn -p KeyPair.snk PublicKey.snk ---从KeyPair.snk文件中提取公钥并将其写入公钥文件PublicKey.snk中。

sn -tp PublicKey.snk >PublicKey.txt ---将公钥信息提取到PublicKey.txt文件中(可以查看公钥)

 

三、延迟加载

这里如果在程序集的开发过程中,有大量的人介入,每个负责编译强名称程序集的人都需要访问包含公钥 密钥对文件,这样就很难保证密钥不会被泄露出去,为了尽量防止这种情况的发生,便诞生了一种叫做延迟签名(delayed signature)的机制,这种机制的运作方式是:
     1) 首先通过sn -p命令产生一个只包含公钥信息的.snk文件,例如:sn -p MyKey.snk MyPubKey.snk,后
        面的这个MyPubKey.snk便是一个只包含公钥信息的.snk文件;
     2) 然后呢通过用true来初始化AssemblyDelaySignAttribute来激活delayed signature,这样开发人员直
        接使用MyPubKey.snk来代替MyKey.snk来进行开发,编译器不会对主模块进行签名,但是会保留出主模
        块中用来签名的空间,并且还会将MyPubKey.snk中的公钥信息插入到主模块清单中的AssemblyDef中,
        并且计算各非主模块的散列值插入到主模块清单的FileDef中。
     3) 最后当开发完毕准备打包部署时,只要使用 sn.exe工具的-R(注意大写)选项就可以完成签名,例如:
        sn.exe -R Assname.exe MyKey.snk。

 

Best Regards,

Charles Chen

msn:gotosunny^msn.com(^替换成@)