检查 SQL 连接字符串是否指定参数

Checking if SQL Connection String specifies a parameter

提问人:Mo B. 提问时间:8/30/2022 最后编辑:Mo B. 更新时间:6/27/2023 访问量:519

问:

我正在寻找一种强大的方法来检查给定的 SQL 连接字符串是否明确指定了某个参数,例如“”。我尝试使用 解析字符串,期望这会告诉我是否指定了键,但它不起作用:Encrypt=...SqlConnectionStringBuilderContainsKey()

System.Data.SqlClient.SqlConnectionStringBuilder x = 
    new("Data Source=.;Initial Catalog=myDb;Integrated Security=True");

bool encryptSpecified = x.ContainsKey("Encrypt"); // returns true :(

澄清

我应该澄清为什么我需要知道参数是否被显式指定。在当前版本的 中,默认值是 ,但在 (in ) 之前是 。因此,为了确保升级到 后应用程序中的向后兼容性,我想将参数设置为 除非用户明确为其指定了值EncryptMicrosoft.Data.SqlClientEncrypttrueSql.Data.SqlClientfalseMicrosoft.Data.SqlClientEncryptfalse

溶液

[基于与@Charlieface的讨论]

// important: *not* Microsoft.Data.SqlClient.SqlConnectionStringBuilder!
System.Data.SqlClient.SqlConnectionStringBuilder scsb = 
    new(connectionString); 
if (!scsb.Encrypted) scsb.Encrypted = false; // this will explicitly set Encrypt
connectionString = scsb.ConnectionString;
C# 连接字符串 System.Data.SqlClient

评论

0赞 Charlieface 8/30/2022
至于将其显式设置为 ,进行重大更改是有原因的。您应该获得适当的证书并确保加密有效,而不仅仅是将其关闭。false
0赞 Mo B. 8/30/2022
@Charlieface我知道。但这是在更好的默认安全性和通过重大更改缠绕所有现有客户之间进行权衡。

答:

3赞 Charlieface 8/30/2022 #1

ContainsKey基本上是无用的,因为它只告诉你一个键是否受支持,而不是字符串是否实际包含它。如果字符串没有该键,则使用默认值。

您可以使用该属性来告诉您值是什么。如果默认值为 (在新版本的 中已更改为 )。EncryptfalsefalsetrueMicrosoft.Data.SqlClient

此外,这比仅仅检查字符串是否包含键更有用,因为它告诉您在运行时实际使用什么值。

var x = new SqlConnectionStringBuilder("Data Source=.;Initial Catalog=myDb;Integrated Security=True");
Console.WriteLine(x.ContainsKey("Encrypt"));

dotnetfiddle

评论

0赞 Mo B. 8/30/2022
我的问题是,它没有区分参数是显式指定为还是只是隐式默认值。Encryptfalse
0赞 Charlieface 8/30/2022
我知道,我指出这应该无关紧要。重要的是在运行时使用什么值,这就是告诉你的Encrypt
0赞 Mo B. 8/30/2022
嗯,但总是作为默认值返回,即使正如您指出的那样,实际上在运行时使用。SqlConnectionStringBuilderfalseEncryptMicrosoft.Data.SqlClienttrue
0赞 Charlieface 8/30/2022
不,我得到新版本 dotnetfiddle.net/7qHiOY 确保不是TrueMicrosoft.Data.SqlConnectionStringBuilderSystem.Data.SqlConnectionStringBuilder
0赞 Mo B. 8/30/2022
是的,我用的是旧版本。我为我的问题添加了一些背景。实际上,对我来说,解决方案是使用旧版本来获取以前的默认值。谢谢。
1赞 Bill Menees 6/20/2023 #2

出于同样的原因,我遇到了同样的问题。我们在小型内部网络上安装了大量 SQL Server,因此我们更希望保留旧的默认行为 .仅仅因为 Microsoft 更改了默认值,就不值得在所有这些机器上麻烦证书。在极少数情况下,我们有云托管的数据库,我们将在服务器上显式配置证书并设置 Encrypt=true。Encrypt=false

我不想继续使用旧类型(如问题的解决方案所建议的那样),因为我的 Directory.Packages.props 文件不再允许引用 System.Data.SqlClient 包。System.Data.SqlClient.SqlConnectionStringBuilder

我的解决方法使用一个简单的正则表达式:

using Microsoft.Data.SqlClient;
...

SqlConnectionStringBuilder builder = new(connectionString);
Regex containsEncrypt = CreateContainsEncryptRegex();
if (!containsEncrypt.IsMatch(connectionString))
{
    builder.Encrypt = false;
}
connectionString = builder.ConnectionString;

...
[GeneratedRegex(@"(?i)(^|;)\s*Encrypt\s*=", RegexOptions.Compiled)]
private static partial Regex CreateContainsEncryptRegex();

评论

1赞 Mo B. 6/21/2023
好主意,您可以使正则表达式更健壮一些(不区分大小写 + 忽略周围的空格)?查看 learn.microsoft.com/en-us/openspecs/sql_server_protocols/...=
0赞 Bill Menees 6/21/2023
关于空白的好点。我已经更新了正则表达式以允许这样做。由于内联 (?i) 选项,正则表达式已经不区分大小写。
1赞 Mo B. 6/27/2023
你不是还需要在前面添加一个空格图案吗?Encrypt
0赞 Bill Menees 6/27/2023
是的!好渔获。谢谢!