不久前,我發佈了一個調試工具:發佈:.NET開發人員必備的可視化調試工具(你值的擁有)不久前,我發佈了一個調試工具:發佈:.NET開發人員必備的可視化調試工具(你值的擁有) 效果是這樣的:之後,有小部分用戶反映,工具不生效~~~然後,建議小部分用戶換個電腦環境試試,就好了~~~於是... ...
背景:
不久前,我發佈了一個調試工具:發佈:.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。 2:as 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.0\Common7\Packages\Debugger\Visualizers\CYQ.Data.dll”位置處)。 在 CYQ.Visualizer.MDataTableVisualizer.Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider) 在 Microsoft.VisualStudio.DebuggerVisualizers.DebugViewerShim.ManagedShim.DelegatedHost.CreateViewer(IntPtr hwnd, HostServicesHelper hsh, SafeProxyWrapper proxy)
這個異常是什麼等會再說,先補充知識點先:
1:as 類型轉換:只檢測上下文中類型是否一致(或存在隱式轉換),若失敗返回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類型無法互轉,這麼多年終於遇上了,說明上的山多還是會見鬼的。
可既然版本號和簽名都一致,又認為簽名無法偽造,那為什麼不呢?