zoukankan      html  css  js  c++  java
  • 为C# as 类型转换及Assembly.LoadFrom埋坑!

    背景:

    不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有)

    效果是这样的:

    之后,有小部分用户反映,工具用不了(没反应或有异常)~~~

    然后,建议小部分用户换个电脑环境试试,有些就好了~~~

    于是,我假定是VS环境下的 Microsoft.VisualStudio.DebuggerVisualizers.dll 的版本不一致引发的。

    因此,一般我都建议用户自己下载源码,重新引用去编绎一下!!!

    由于该工具一直在CSDN论坛的VB.NET版块置顶着。

    考虑到受众多,中间还偷偷升级过几回,解决了抛异常的问题,不过仍没有从根本性解决~~~~

    这两天,有个叫子寒的同学,找上了我,希望我帮他解决这个问题。

    我试着重新编绎了新版本发给他,都反馈木有效果。

    只好让他下载源码,并在他电脑上进行远程调试。

    昨晚处理到深夜1点半,终于:把发现的两个坑给埋了!!!

    下面介绍下这两个坑:

    1:as 转换的坑:

    先看一段源码,这是拿到反序列化的结果,转Table,再绑定:

     protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
            {
                MDataTable dt = objectProvider.GetObject() as MDataTable;
                FormCreate.BindTable(windowService, dt, null);
            }

    在这段代码中,调试的结果:

    1:objectProvider.GetObject() 拿到的对象是MDataTable,GetType也返回的CYQ.Data.Table.MDataTable。
    
    2as MDataTable 却返回了null ?

    咦?一个大大的问号在我面前,同样的类型,怎么as不过去?

    于是我把代码改了一下:

    MDataTable dt=(MDataTable)objectProvider.GetObject()

    抛异常了:

    ************** 异常文本 **************
    System.InvalidCastException: [A]CYQ.Data.Table.MDataTable 无法强制转换为 [B]CYQ.Data.Table.MDataTable。
    类型 A 源自“CYQ.Data, Version=5.7.5.5, Culture=neutral, PublicKeyToken=null”(在字节数组的上下文“LoadNeither”中)。
    类型 B 源自“CYQ.Data, Version=5.7.5.5, Culture=neutral, PublicKeyToken=null”(在上下文“LoadFrom”中的“C:Program Files (x86)Microsoft Visual Studio 12.0Common7PackagesDebuggerVisualizersCYQ.Data.dll”位置处)。 在 CYQ.Visualizer.MDataTableVisualizer.Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider) 在 Microsoft.VisualStudio.DebuggerVisualizers.DebugViewerShim.ManagedShim.DelegatedHost.CreateViewer(IntPtr hwnd, HostServicesHelper hsh, SafeProxyWrapper proxy)

    这个异常是什么等会再说,先补充知识点先:

    1as 类型转换:只检测上下文中类型是否一致(或存在隐式转换),若失败返回null,不抛异常。
    
    2:强制类型转换:尝试进行类型转换,转换失败时,抛出异常。

    好吧,第一个坑,相同的类型,没有异常,埋的够深!!!

    AS叫了:这坑不能怪我,要怪就怪Assembly.LoadFrom,谁让你们把我们分隔在不同的上下文中。

    2:Assembly.LoadFrom 的坑

    这里再贴一段详细的异常信息:

    mscorlib
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
    ----------------------------------------
    Microsoft.VisualStudio.Platform.AppDomainManager
        程序集版本:12.0.0.0
        Win32 版本:12.0.21005.1
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/Microsoft.VisualStudio.Platform.AppDomainManager/v4.0_12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.Platform.AppDomainManager.dll
    ----------------------------------------
    System
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
    ----------------------------------------
    System.Xml
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
    ----------------------------------------
    System.Configuration
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
    ----------------------------------------
    System.Windows.Forms
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
    ----------------------------------------
    System.Drawing
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
    ----------------------------------------
    Microsoft.VisualStudio.DebuggerVisualizers
        程序集版本:12.0.0.0
        Win32 版本:12.0.21005.1
        基本代码:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll
    ----------------------------------------
    CYQ.Visualizer
        程序集版本:2.0.0.5
        Win32 版本:2.0.0.5
        基本代码:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Visualizer.dll
    ----------------------------------------
    CYQ.Data
        程序集版本:5.7.5.5
        Win32 版本:5.7.5.5
        基本代码:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Data.DLL
    ----------------------------------------
    System.Data
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll
    ----------------------------------------
    System.Core
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
    ----------------------------------------
    CYQ.Data
        程序集版本:5.7.5.5
        Win32 版本:12.0.21005.1
        基本代码:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll
    ----------------------------------------
    System.Numerics
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Numerics/v4.0_4.0.0.0__b77a5c561934e089/System.Numerics.dll
    ----------------------------------------
    System.Transactions
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Transactions/v4.0_4.0.0.0__b77a5c561934e089/System.Transactions.dll
    ----------------------------------------
    System.EnterpriseServices
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.EnterpriseServices/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.EnterpriseServices.dll
    ----------------------------------------
    System.Windows.Forms.resources
        程序集版本:4.0.0.0
        Win32 版本:4.0.30319.34209 built by: FX452RTMGDR
        基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms.resources/v4.0_4.0.0.0_zh-Hans_b77a5c561934e089/System.Windows.Forms.resources.dll
    ----------------------------------------
    ************** 已加载的程序集 **************

     异常里核心的两段:

    CYQ.Visualizer
        程序集版本:2.0.0.5
        Win32 版本:2.0.0.5
        基本代码:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Visualizer.dll
    ----------------------------------------
    CYQ.Data
        程序集版本:5.7.5.5
        Win32 版本:5.7.5.5
        基本代码:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Data.DLL
    
    CYQ.Data
        程序集版本:5.7.5.5
        Win32 版本:12.0.21005.1
        基本代码:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll

    从上面的异常错误信息中,第一眼看是要蒙B的,毕竟少见多怪啊~~~~

    大概花了8分钟,终于反应过来了,经过仔细的思考,可以发现:

    1:CYQ.Data 被CYQ.Visualizer.dll加载是在同一目录下。
    
    2:被Microsoft.VisualStudio.DebuggerVisualizers.dll加载却是在(上下文“LoadNeither”中,鬼知道这个LoadNeither是什么)。

    于是,同一个dll被加载成两个不同路径,导致上下文环境不一样,而不能互转~~~~

    为什么大部分正常,小部分环境会这么处理呢,目前无从知道,微软也是爱造坑的~~~

    好吧,坑已经知道了,接下来如何埋才是重点:

    1:埋坑思维一:测试下Assembly.Load、Assembly.LoadFile、Assembly.LoadFrom

    写了几段测试代码:

     string filePath = AppDomain.CurrentDomain.BaseDirectory + "cyq\CYQ.Data.dll";
                byte[] bytes = File.ReadAllBytes(filePath);
                Assembly ass = Assembly.Load(bytes);
                object o = ass.CreateInstance("CYQ.Data.Table.MDataTable");
     MDataTable dt = (MDataTable)o;

    失败!

     string filePath = AppDomain.CurrentDomain.BaseDirectory + "cyq\CYQ.Data.dll";
     Assembly ass = Assembly.LoadFrom(filePath);
     Assembly.LoadFile(filePath);
    ...省略...

    都失败!!

    测试这三个方法,主要是想看看有没有啥本质的不一样,特别是和强签名合在一起后~~~

    把dll加个强签名试试~~~

    仍失败~~~~

    看来,我想多了,不同的dll路径加载的对象转换这条路是不通的了~~~~

    2:埋坑思维二:强签名DLL,并注册到GAC中

    理论上来说:该方式100%是可行的,毕竟路径的引用都是一致的。

    方式也简单:通过代码加个注册的命令也不是什么难事~~~~

    还是思考有没有其它更简洁的方式!

    3:埋坑思维三:找个稳定的中介

    既然问题出现在序列化前的MDataTable和反序列化后的MDataTable在不同上下文的dll而导致的。

    那就就找一种第三方中介了:MDataTable=>中介(序列化)=》中介(反序列化)=>MDataTable

    不用动脑,就可以想到两种:json或 DataTable。

    于是代码就动起来了:

    序列化时,用DataTable

    反序列化时:

    打完收工,重新编绎,发给用户测试,正常通过~

    工具下载地址:

    http://www.cnblogs.com/cyq1162/p/6027051.html

    总结:

    1:这么多年,第一次栽坑在as转换上,也许是没想到,也许是万万想不到。

    2:不同的路径加载的相同的dll类型无法互转,这么多年终于遇上了,说明上的山多还是会见鬼的。

    可既然版本号和签名都一致,又认为签名无法伪造,那为什么不呢?

  • 相关阅读:
    grep 命令操作
    vi & vim复制,粘贴,剪切文本
    β版本第四次冲刺
    β版本第三次冲刺
    β版本第二次冲刺
    β版本第一次冲刺
    华为软件开发云,个人评测及体会
    事后诸葛亮
    【Alpha】团队课程展示
    团队Alpha博客链接目录
  • 原文地址:https://www.cnblogs.com/cyq1162/p/6212200.html
Copyright © 2011-2022 走看看