将框架从.NET6升级到8,顺便将各种依赖包也升级,容器化部署到测试环境后,SQL Server连接不了了:
[2024-05-13 13:48:10 ERR] [Microsoft.EntityFrameworkCore.Database.Connection] An error occurred using the connection to database 'Demo' on server '127.0.0.1'. [2024-05-13 13:48:10 ERR] [Microsoft.EntityFrameworkCore.Query] An exception occurred while iterating over the results of a query for context type 'DemoDbContext'. Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 31 - Encryption(ssl/tls) handshake failed) ---> System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
以前也遇到过类似的问题,是通过修改TLS的最低支持版本来解决,但这次是升级了依赖导致的无法连接数据库,之前的解决方式不起作用,说明对这个问题的理解还不到位。
在github上提了个issue,原来是在EFCore 7这个版本有个breaking change:连接字符串中的Encrypt
参数的默认值有False变为了True,那么在连接数据库时就会尝试建立加密连接,也就是这个过程失败了。
Encrypt=False,若SQL Server配置了强制使用加密连接也会取尝试建立加密连接
失败原因是SQL Server的证书没有在客户端通过校验。下面是本机进行复现的错误信息:
那么解决方案有以下几种:
-
给SQL Server安装正确的证书
-
在连接字符串中添加
TrustServerCertificate=True
-
连接字符串中设置
Encrypt=False
关于Encrypt
和TrustServerCertificate
参数,可参考:Use TrustServerCertificate
Encrypt connection string/attribute | Trust Server Certificate connection string/attribute | Result |
---|---|---|
No/Optional | Ignored | No encryption occurs. |
Yes/Mandatory | No | Encryption occurs only if there's a verifiable server certificate, otherwise the connection attempt fails. |
Yes/Mandatory | Yes | Encryption always occurs, but may use a self-signed server certificate. |
Strict1 | Ignored | Encryption always occurs and must use a verifiable server certificate, otherwise the connection attempt fails. |
小结
结合本次及之前遇到的问题,SQL Server连接报错,有以下几种原因:
-
客户端/服务端间TLS版本不兼容
-
服务器证书有问题,客户端校验不通过
最后附一张HTTPS连接的建立过程图: