[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數據庫了。html

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

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,問題依舊。。。折騰了幾天,實在找不出緣由,就將問題放之一邊。github

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

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

太奇怪了!怎麼會與SQL Server有關?因而將阿里雲RDS換成了另外1臺本身安裝的SQL Server,但也是一樣的問題。如今問題變成了:一樣的應用程序,訪問1臺SQL Server正常,訪問另外一臺就出錯。因而將解決問題的焦點放到了比較這2臺SQL Server的不一樣之處,但經過SQL Profiler進行跟蹤,未發現有任何不一樣。windows

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

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

相關文章
相關標籤/搜索