[ASP.NET 5]終於解決:Unable to load DLL 'api-ms-win-core-localization-obsolete-l1-2-0.dll'


11月12日,驚喜地發現SqlClient(System.Data.SqlClient.dll)跨平台了(對應的nuget包包是runtime.unix.System.Data.SqlClient),終於可以在Linux上基於.NET Core運行ASP.NET 5程序訪問SQL Server數據庫了。

於是,立馬更新dnx至rc2,用之前已經寫好的、用EF7訪問SQL Server數據庫的ASP.NET 5示例程序,分別在2台Linux服務器上進行測試。但測試時遇到了一個非常奇怪的問題:其中1台Linux服務器上可以正常訪問SQL Server數據庫,而另外1台Linux服務器上運行時總是出現這樣的錯誤:

DllNotFoundException: Unable to load DLL 'api-ms-win-core-localization-obsolete-l1-2-0.dll': The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)

這2台Linux服務器分別訪問的是2台不同的SQL Server,能正常訪問的服務器用的是自己在純英文操作系統上安裝的SQL Server,不能正常訪問的服務器用的是阿里雲RDS。

當時以為是這2台Linux服務器的系統環境不一樣引起的,於是分別重裝操作系統,重新安裝dnx,問題依舊。。。折騰了幾天,實在找不出原因,就將問題放之一邊。

今天(11月19日),微軟正式發布了ASP.NET 5 RC1,於是又基於ASP.NET 5 RC1測試了一下,問題還是依舊。

但是今天在測試時,進行了一個之前遺漏的測試,在出問題的服務器上訪問不出問題的服務器所用的SQL Server,結果問題立馬消失。

太奇怪了!怎么會與SQL Server有關?於是將阿里雲RDS換成了另外1台自己安裝的SQL Server,但也是同樣的問題。現在問題變成了:同樣的應用程序,訪問1台SQL Server正常,訪問另一台就出錯。於是將解決問題的焦點放到了比較這2台SQL Server的不同之處,但通過SQL Profiler進行跟蹤,未發現有任何不同。

后來,用EF遷移命令訪問數據庫:

dnx ef database update

也是同樣的錯誤:

System.DllNotFoundException: Unable to load DLL 'api-ms-win-core-localization-obsolete-l1-2-0.dll': The specified module could not be found.
 (Exception from HRESULT: 0x8007007E)
   at System.Data.LocaleInterop.LCIDToLocaleName(UInt32 Locale, StringBuilder lpName, Int32 cchName, Int32 dwFlags)
   at System.Data.LocaleInterop.LcidToLocaleNameInternal(Int32 lcid)
   at System.Data.LocaleInterop.GetDetailsInternal(Int32 lcid)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at System.Data.SqlClient.TdsParser.GetCodePage(SqlCollation collation, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.TryProcessEnvChange(Int32 tokenLength, TdsParserStateObject stateObj, SqlEnvChange[]& sqlEnvChange)

但是調用棧的信息不一樣,當看到 TdsParser.GetCodePage 方法,突然想到是不是與Codepage有關?但是SQL Profiler看不到任何與Codepage的信息。。。

是不是漏掉了什么?是不是在SqlClient與SQL Server交互時,還有一些信息被漏掉了?得要看到它們之間的所有交互信息,怎么看呢?

看網絡交互信息,最有效的方法非網絡抓包莫屬(所以說抓包是程序員的基本功之一)。於是在SQL Server服務器上用Wireshark抓包。。。

果然逮着了Codepage相關的東西,在SqlClient登錄至SQL Server之后,SQL Server響應給客戶端的內容中有這樣的信息:

看!Codepage: 2052,它表示的是中文(Chinese - China),問題很可能與這里返回的Codepage有關。

但SQL Server中什么設置會影響到這里返回的Codepage值呢?搜索"windows change sql server codepage",找到了線索,原來就是Database Collation的設置。

比較了一下這2台SQL Server中對應數據庫的Collation設置,沒出問題的SQL Server設置的是SQL_Latin1_General_CP1_CI_AS,出問題的SQL Server設置的是Chinese_PRC_CI_AS。

於是將Collation由Chinese_PRC_CI_AS改為SQL_Latin1_General_CP1_CI_AS,問題立馬解決!

當然,問題的根源不是SQL Server的Collation設置,而是跨平台的System.Data.SqlClient.dll不能正確處理Collation為Chinese_PRC_CI_AS的情況,這算是corefx中System.Data.SqlClient實現的一個bug。

不管怎么樣,總算找到了問題的真正原因,暫時也有臨時解決方法,在Linux服務器上基於.NET Core運行ASP.NET 5程序訪問SQL Server已經成為現實。

【相關博文】

.NET跨平台之旅:升級至ASP.NET 5 RC1,Linux上訪問SQL Server數據庫

【更新】

該問題已被修復,詳見 dotnet/corefx/pull/4958


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM