我有一个用c#构建的通知应用程序,用于通知数据库中的任何更改。该应用程序在后台运行。但问题是在应用程序启动后如果关闭互联网,则应用程序抛出SQLException。我用try catch来处理异常。但我希望我的应用程序尝试连接数据库,并在建立连接时返回到主代码。
try
{
using (SqlConnection connection =
new SqlConnection(GetConnectionString()))
{
//i want to return here when the connection is reestablished
using (SqlCommand command =
new SqlCommand(GetListenerSQL(), connection))
{
connection.Open();
// Make sure we don't time out before the
// notification request times out.
command.CommandTimeout = NotificationTimeout;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
messageText = System.Text.ASCIIEncoding.ASCII.GetString((byte[])reader.GetValue(13)).ToString();
// Empty queue of messages.
// Application logic could parse
// the queue data and
// change its notification logic.
}
object[] args = { this, EventArgs.Empty };
EventHandler notify =
new EventHandler(OnNotificationComplete);
// Notify the UI thread that a notification
// has occurred.
this.BeginInvoke(notify, args);
}
}
}
catch(SqlException e)
{
}
没有goto声明就可以做到这一点。我宁愿避免使用goto语句。
我会将重试逻辑移出查询方法。我在某个地方见过一个很好的重试库,但我现在找不到它。
public void StartListener()
{
var message = GetMessage();
//process message in some way
object[] args = { this, EventArgs.Empty };
EventHandler notify = OnNotificationComplete;
this.BeginInvoke(notify, args);
}
private const int TimeoutStep = 2000;
private const int MaxTimeout = 10000;
private string GetMessage(int timeout = 0)
{
//prevent loop of endless retries
if (timeout >= MaxTimeout)
{
//optional: define your own Exception class
throw new MaxTimeoutException();
}
try
{
Thread.Sleep(timeout);
return GetMessageFromDatabase();
}
catch (SqlException ex)
{
//log ex in debug mode at least
return GetMessage(timeout + TimeoutStep);
}
}
private string GetMessageFromDatabase()
{
string message = null;
using (var connection = new SqlConnection(GetConnectionString()))
{
using (var command = new SqlCommand(GetListenerSQL(), connection))
{
connection.Open();
command.CommandTimeout = NotificationTimeout;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
message = System.Text.ASCIIEncoding.ASCII.GetString((byte[])reader.GetValue(13));
}
}
}
}
return message;
}
从@Archer的建议我得到了解决方案。在catch块中,我再次调用该方法,该方法在一段合适的时间后使用此连接。就像是
public void StartListener()
{
try
{
using (SqlConnection connection =
new SqlConnection(GetConnectionString()))
{
//i want to return here when the connection is reestablished
using (SqlCommand command =
new SqlCommand(GetListenerSQL(), connection))
{
connection.Open();
// Make sure we don't time out before the
// notification request times out.
command.CommandTimeout = NotificationTimeout;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
messageText = System.Text.ASCIIEncoding.ASCII.GetString((byte[])reader.GetValue(13)).ToString();
// Empty queue of messages.
// Application logic could parse
// the queue data and
// change its notification logic.
}
object[] args = { this, EventArgs.Empty };
EventHandler notify =
new EventHandler(OnNotificationComplete);
// Notify the UI thread that a notification
// has occurred.
this.BeginInvoke(notify, args);
}
}
}
catch(SqlException e)
{
Thread.Sleep(2000);
StartListener();
}
}
如果它失败了你应该调用一个计时器,计时器应该调用后台工作者。编写功能以检查后台工作人员的连接。如果它是真的你应该停止计时器。并调用通常的过程