同事報案。某個使用 Managed ODP.NET 的測試網站吐出以下錯誤
Error: The type initializer for 'OracleInternal.Common.ProviderConfig' threw an exception.
同事一度懷疑跟 ODP.NET 版本有關,但依經驗,如為版本問題錯誤訊息會確指出所需元件全名、版號等資訊。為調查問題,我直接在 IIS主機現場撰寫 Tets.aspx 偵錯,測試程式一用到 new Oracel.ManagedDataAccess.Client.OralceConnection() 就吐出以下錯誤:
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: An error occurred creating the configuration section handler for oracle.manageddataaccess.client: Could not load file or assembly 'Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Source File: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config Line: 14
錯誤訊息提到 Oracle.ManagedDataAccess.Client 4.121.1.0,鐵證如山,證實是 Managed ODP.NET 版本不相容,而machine.config 的第 14 行正是
<section name="oracle.manageddataaccess.client" type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
由此推測,問題出在該主機有安裝 Managed ODP.NET 4.121.1,而專案升級到 ODP.NET 4.121.2,但在 web.config 遺漏 bindingRedirect將所有 Managed ODP.NET 版本導向 4.121.2的設定,解析 web.config 時先引用了 machin.config,提到需要 4.121.1 版,但 bin 目錄下卻是 4.121.2 版,便爆出版本不符錯誤。
但有個問題是,為什麼專案程式抛出的錯誤訊息跟 Test.aspx 測試不同?追查出錯的程式片段,發現它是透過 Autofac 取得資料來源物件,屬於動態載入,推測是造成導致錯誤訊息不同的原因,使用以下程式剖析 InnerException,可證明 configuration section handler 錯誤外層又包一層OracleInternal.Common.ProviderConfig 錯誤:
<%@ Page Language="C#" %>
<%
//var cn = new Oracle.ManagedDataAccess.Client.OracleConnection("...");
var dp = MyAutofacFactory.Resolve<IEntityDataProvider>();
try
{
var cn = dp.CreateConnection(); //其中邏輯為 new OracleConnection後回傳
}
catch (Exception ex)
{
Response.Write(ex.Message);
Response.Write("<hr />");
Response.Write(ex.InnerException.Message);
}
%>
測試結果如下:
• The type initializer for 'OracleInternal.Common.ProviderConfig' threw an exception.
• An error occurred creating the configuration section handler for oracle.manageddataaccess.client: Could not load file or assembly 'Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) (C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config line 14)
最後回到「為什麼第一時間沒能看出版本不相容?」
問題出在該專案 try catch 了資料庫讀寫作業,但發生錯誤時只抛出 Exception.Message,卻沒保留或顯示 InnerException 或 Callstack 資訊(如要省事,改取 Exception.ToString() 即涵蓋所有重要資訊 ),遺失可供追查辦案的重要線索,是實務上使用 try catch 易被疏忽的細節,此一經驗提供大家參考。