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