Wam*_*ama 1 .net c# sql sql-server connection-string
我正在尝试设置一种方法,该方法将尝试首先在默认端口(1433)上连接到 SQL Server,然后在失败时在其他端口(例如 7777)上连接。
我想避免重建连接字符串并在失败时尝试再次连接,因为此方法将按照配置的时间间隔执行,并且我希望消除尽可能多的开销。
我尝试了以下方法(由ConnectionStrings提供)
public void EstablishConnection()
{
string ConnectionString = "Data Source=127.0.0.1; Failover Partner=127.0.0.1,7777; Initial Catalog=foo;Connection Timeout = 3; Persist Security Info =True;User ID=<id>;Password=<password>";
try
{
SqlConnection Connection = new SqlConnection(ConnectionString);
Connection.Open();
}
catch (SqlException)
{
// Connection failed
}
}
Run Code Online (Sandbox Code Playgroud)
但根据这篇文章我的测试,它并没有按照我的预期方式工作。
我可以通过执行以下操作轻松解决此问题:
public void EstablishConnection()
{
string ConnectionString = "Data Source=127.0.0.1;Initial Catalog=foo;Connection Timeout = 3; Persist Security Info =True;User ID=<id>;Password=<password>";
try
{
SqlConnection Connection = new SqlConnection(ConnectionString);
Connection.Open();
}
catch (SqlException)
{
try
{
string ConnectionString = "Data Source=127.0.0.1,7777;Initial Catalog=foo;Connection Timeout = 3; Persist Security Info =True;User ID=<id>;Password=<password>";
SqlConnection Connection = new SqlConnection(ConnectionString);
Connection.Open();
}
catch (SqlException)
{
// Connection failed
}
}
}
Run Code Online (Sandbox Code Playgroud)
但这感觉就像意大利面条代码和整体糟糕的做法。
此外,在实际应用程序中,我不会从配置文件中获取完整的连接字符串,而是从配置文件中提取参数并从那里构建配置字符串。
首先,让我们定义一个辅助方法来创建并打开尝试所有给定端口的连接:
private SqlConnection TryEstabilishConnection(params int?[] portNumbers) {
foreach (int? portNumber in portNumbers)
{
var connectionString = CreateConnectionStringBuilder();
if (portNumber != null)
connectionString.DataSource += $",{portNumber}";
try {
var connection = new SqlConnection(connectionString.ToString());
connection.Open();
return connection;
}
catch (SqlException) {
// Attempt failed, log?
}
}
// Connection failed with all given ports...
return null;
}
Run Code Online (Sandbox Code Playgroud)
CreateConnectionStringBuilder()方法从配置中读取参数并返回一个可用的SqlConnectionStringBuilder对象:
private SqlConnectionStringBuilder CreateConnectionStringBuilder() {
// ...
}
Run Code Online (Sandbox Code Playgroud)
您的代码将是:
public void EstabilishConnection() {
// You can specify more than one alternative port
var connection = TryEstabilishConnection(null, 7777, 58900);
if (connection == null) {
// Oops!
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您没有指定任何端口号,它将尝试使用默认端口号 (1433),但也会尝试与 1434 建立 UDP 连接以请求动态分配的 TCP 端口(只有在禁用此机制的情况下,替代端口的想法才有用) SQL 服务器配置)。
另请注意,有时连接因网络相关错误而无法工作,但 SQL Server 实例正在默认端口上侦听,您可能需要使用重试模式,我仅在此处概述代码:
private SqlConnection TryEstabilishConnection(params int?[] portNumbers) {
foreach (int? portNumber in portNumbers) {
var connectionString = CreateConnectionStringBuilder();
if (portNumber != null)
connectionString.DataSource += $",{portNumber}";
var connection = TryEstabilishConnection(connectionString.ToString());
if (connection != null)
return connection;
}
// Connection failed with all given ports...
return null;
}
private SqlConnection TryEstabilishConnection(string connectionString) {
for (int i=0; i < RetriesOnError; ++i) {
try {
var connection = new SqlConnection(connectionString);
connection.Open();
return connection;
}
catch (SqlException) when (i < RetriesOnError - 1) {
Thread.Sleep(DelayBeforeRetry);
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
这些常量只是指示性的,网络错误可能需要更长的延迟(或更多的尝试),但您最终可能需要等待太长时间才能收到连接不可用的通知(如果这种情况经常发生,那么您应该更改您的用户体验告知用户正在发生的事情):
private const int RetriesOnError = 5;
private const int DelayBeforeRetry = 1000;
Run Code Online (Sandbox Code Playgroud)
调用代码不变。您也可以使用相同的模式在正常操作期间重试,另请参阅从 C# 调用 SQL Server 时知道何时重试或失败?。在这种情况下,我建议保存有效的连接,如果默认端口不可用,则不要再次尝试。
最后一点:(Failover Partner应该)仅适用于镜像数据库,据我所知,它不是您可以在没有任何其他 SQL Server 配置的情况下使用的替代方案 Data Source(但我想说它可能是一个很好的功能)。