IIS部署ASP.Net Framework 4.8站点时Microsoft.Data.SqlClient优先访问bin目录SNI.dll问题
问题根因
- 现有代码存在架构选择逻辑错误:判断64位进程时错误选择了x86版本的SNI.dll,复制的dll架构不匹配触发加载失败,会自动回退到bin目录检索兼容版本
- Microsoft.Data.SqlClient加载原生SNI.dll的默认搜索顺序为:进程当前工作目录(IIS站点根目录/bin)> 系统目录 > 托管程序集所在目录,因此即使SNI.dll和Microsoft.Data.SqlClient.dll同属影子副本目录,也不会被优先加载
修复步骤
- 第一步:修正架构匹配逻辑
将原代码中的架构判断逻辑修正,避免复制错误版本的SNI.dll:
// 原错误逻辑:64位进程取x86版本,已修正 var moduleName = Environment.Is64BitProcess ? "x64\\SNI.dll" : "x86\\SNI.dll";
- 第二步:提前主动加载正确路径的SNI.dll
在Global.asax的Application_Start方法最开头、任何数据库访问逻辑执行前,先调用Win32 API加载影子副本路径下的SNI.dll,避免后续SqlClient去bin目录检索:
using System.Runtime.InteropServices; // 声明LoadLibrary API [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); // 复制SNI.dll到影子副本目录后立即调用加载 var targetFile = Path.Combine(sqlClientShadowPath, "SNI.dll"); if (File.Exists(targetFile)) { LoadLibrary(targetFile); }
- 第三步:将影子副本目录加入系统DLL搜索路径
如果主动加载仍然不生效,可以将Microsoft.Data.SqlClient的影子副本目录加入进程DLL搜索优先级列表,执行时机同样放在Application_Start最开头:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool SetDllDirectory(string lpPathName); // 复制完SNI.dll后调用 SetDllDirectory(sqlClientShadowPath);
- 第四步(可选替代方案):升级Microsoft.Data.SqlClient版本
将Microsoft.Data.SqlClient升级到2.1.x及以上兼容版本,该版本开始优化了SNI.dll的加载逻辑,原生支持从托管程序集所在目录优先检索SNI.dll,不需要额外做影子副本复制逻辑,且兼容EF Core 3.1.16的依赖要求。
内容的提问来源于stack exchange,提问作者GraemeMogo
相关产品推荐
相关产品推荐

