【茶包射手專欄】坎坷ODP.NET 10升級之路
有台Web,存取Oracle的程式不定期會出現以下錯誤:
- [OracleException: ORA-01036: 變數名稱號碼無效] Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure) +751 Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior) +2430 Oracle.DataAccess.Client.OracleCommand.ExecuteReader() +86
- [IndexOutOfRangeException: 在結果集中找不到指定的資料欄] Oracle.DataAccess.Client.OracleDataReader.GetOrdinal(String name) +582
這兩個錯誤表面上是OracleParameter及SELECT欄位沒寫好,理應很好Debug,但巧妙之處在於平時程式都正常運作無誤,不定期才會發生上述錯誤,更難解釋的是,IISRESET後就網頁就可恢復正常好一陣子...
由以上線索看來,我推測問題跟ODP.NET有關,跟同事討論後,由於連線DB已是Oracle 10,而目前網站用的ODP.NET版本為9207,決定把ODP.NET升級到10換換手氣。
到Oracle網站下載了ODAC1020221.exe,高高興興裝好,才發現程式仍繼續用ODP.NET 9207,爬了一下安裝說明,才發現原來它預設並不會幫你套用Policy強制改用新版ODP.NET。
解決方式是安裝$Oracle10.2Home$\ODP.NET\PublisherPolicy\1.x\Policy.9.2.Oracle.DataAccess.dll到GAC中。安裝Policy導向後,果然原本用ODP.NET 9207的網頁就自動改抓10.2版(為了區別起見,我故意將9.2的network/admin/tnsnames.ora搬走,如果錯用9.2,會出現ORA-12154 TNS無法解析服務ID的訊息)。
但麻煩事來了,原來從ODP.NET 10.2版起,Oracle.DataAccess.dll的版號不再沿用先前的9.*, 10.*而是分成.NET 1.1及.NET 2.0兩顆dll,版號分別為變1.102.2.20, 2.102.2.20,Policy.9.2.Oracle.DataAccess.dll會將網頁參考的ODP.NET 9207導成1.102.2.20版;要命的是網頁參考了另一顆元件MyWebControl,它也參考了ODP.NET 9207,你猜怎麼著,.NET Framework覺得MyWebControl原本參考的可是9.2版,哪有回頭去參考1.102版的道理(就算它比較新)?
CS1705: Assembly 'MyWebControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' uses 'Oracle.DataAccess, Version=9.2.0.700, Culture=neutral, PublicKeyToken=89b483f429c47342' which has a higher version than referenced assembly 'Oracle.DataAccess, Version=1.102.2.20, Culture=neutral, PublicKeyToken=89b483f429c47342'
不想去跟這問題拼命,也不想要求相關人員用新版ODP.NET Rebuild MyWebControl,研究了一下,發現改成1.*/2.*是10.2以後的事,ODP.NET 10.1還是遵循古法,採用10.1.0.4的編碼慣例,應可避開上述坑洞。於是移除ODP.NET 10.2,重裝ODP.NET 10.1,安裝程式自己會連Policy強制升版一併裝妥,IISRESET後,網頁終於順利跑將起來。
壞消息是,先前的OracleParameter鬼問題並沒有因為換了10.1而解決,看來還得繼續博鬥下去...