【发布时间】:2014-04-08 18:06:34
【问题描述】:
我有一个在 .NET 4.5 中运行的 Windows 服务。一切正常。但是,当我的服务遇到 SqlException 时,它会挂起(变成僵尸)。
我有一个计时器 (System.Timers),它调用 process。在process 中,找到cmd.ExecuteReader()。如果我从存储过程中删除EXECUTE 权限,我会收到SqlException(如预期的那样)。发生这种情况时,服务会挂起。
我本来希望try {} catch 块之一捕获异常并优雅地退出该方法。但是,系统似乎挂起此呼叫。我在代码中有许多 Trace 语句。我删除了它们以便于阅读。
private void TimerForNotification_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimerForNotification.Stop();
int count = new GetSMSNotifications().process();
TimerForNotification.Start();
}
public int process()
{
int count = 0;
// Get the ConnectionStrings collection.
ConnectionStringSettings connections = ConfigurationManager.ConnectionStrings["DE_OLTP"];
try
{
using (SqlConnection conn = new SqlConnection(connections.ConnectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand("[dbo].[get_SMSToSend]", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
try
{
SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
while (dr.Read())
{
// increment counter
count++;
string destinationAddress = Convert.ToString(dr[dr.GetOrdinal("DestinationAddress")]);
string alertMessage = Convert.ToString(dr[dr.GetOrdinal("Content")]);
// Send out the notification
sendPush(destinationAddress, alertMessage);
}
dr.Close();
}
catch (SqlException se)
{
DELog.Log.Error(se);
}
}
}
catch (Exception ex)
{
DELog.Log.Error(ex);
}
return count;
}
有趣的是,我创建了一个调用上述方法的控制台应用程序,try {} catch 块按预期工作。
我在事件日志中没有看到任何未处理的异常。
想法?
【问题讨论】:
-
究竟挂在哪里 SqlDataReader dr = cmd.ExecuteReader ?
-
它挂在语句上。换句话说,我在 cmd.ExecuteReader() 调用之前和之后直接放置了一个 Trace 语句。 before 语句被写入日志文件。然而, after 声明没有。在我提到的控制台应用程序中,我能够单步进入 process 方法并看到此语句发生异常。
-
附带说明,将
SqlDataReader和在using语句中使用它的while循环包装起来——就像你对SqlConnection和使用它的代码所做的那样.如果在运行cmd.ExecuteReader(CommandBehavior.CloseConnection)时存在SqlException,则您对dr.Close()的显式调用将永远不会发生;并且在重构使用using语句后您将不需要它。
标签: c# sql-server windows-services sqlexception