同事報案,某網站部署至新主機出現錯誤:
[OracleException (0x80004005): 提供者與 Oracle 從屬端版本不相容]
Oracle.DataAccess.Client.OracleInit.Initialize() +517
Oracle.DataAccess.Client.OracleParameter..cctor() +29[TypeInitializationException: The type initializer for 'Oracle.DataAccess.Client.OracleParameter' threw an exception.]
Oracle.DataAccess.Client.OracleParameter..ctor(String parameterName, Object obj) +0
又是ODP.NET跟Oracle Client檔案的匹配老問題,先前處理過兩回,都是改權限加IISRESET解決,這回故技重施卻無效… 是新茶包!趕緊著裝,打綁腿紥S腰帶,提槍快跑前進。
先檢查PATH環境變數:
發現主機上裝了好多版本的Oracle Client!共有D:\OracleR5、D:\Oracle、D:\Oracle2三個目錄,後兩者又各裝了32與64位元版,總共五套。
下一步要找出ODP.NET使用哪一套Oracle Client程式庫。去吧!Process Monitor,就決定是你了。
Process Monitor記錄(註:已篩選Path包含Oracle的項目)有不合理之處:網站程式先取得Oracle2\product\11.2.0\client_32\bin\oci.dll,之後嘗試在同目錄找不到OraOps11w.dll,便依著PATH環境變數找檔案,在Oracle5R找到OraOpsw11.dll,隨後則繼續使用Oracle2下的檔案。
懷疑所謂的「提供者與 Oracle 從屬端版本不相容」是混雜Oracle2與OracleR5兩個不同版本Oracle Client檔案造成。由Process Monitor記錄找到另一則線索:Registry HKLM\SOFTWARE\Wow6432Node\ORACLE\ODP.NET\2.112.1.0\DllPath (註:在64位元Windows,64位元版Oracle Client的Registry在HKLM\SOFTWARE\ORACLE,32位元版則在HKLM\SOFTWARE\Wow6432Node\ORACLE)
打開RegEdit找到DllPath機碼,瞬時恍然大悟!之前只知道32位元版跟64位元版的ODP.NET有能力自己找到對的Oracle Client版本,卻不知其所以然。原來魔法藏在這裡-每個ODP.NET版本有自已的Registry,其中包含DllPath設定指向配合的Oracle Client路徑。
檢查Registry得知2.112.1.0指向D:\Oracle2,2.112.3.0及4.112.3.0指向D:\OracleR5。問題網站使用ODP.NET 11.2.1,故由Registry找到D:\Oracle2,後來發現缺少OraOpsw11.dll,改以PATH環境變數找檔,最後到OracleR5抓交替(但抓到的是2.112.3.0版),由於跟其他2.112.1.0版程式不相容,轟一聲就爆炸了~
追查D:\Oracle2 OraOpsw11.dll缺檔原因,發現D:\Oracle2安裝不完整,少掉不少檔案,D:\Oracle比較像完整的2.112.1 Client安裝目錄。我動手修改上圖中的DllPath,將D:\Oracle2改成D:\Oracle,IISRESET後,錯誤消失。
問題排除,額外收獲是學到ODP.NET尋找Oracle Client檔案的邏輯,收隊!