【问题标题】:C# Windows Service SqlCommand HangsC# Windows 服务 SqlCommand 挂起
【发布时间】: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


【解决方案1】:

问题解决了。我的服务出现挂起的原因是因为我缺少对Entity.Framework.dll 的引用。当服务遇到异常时,找不到 EF dll。我在日志记录层中使用 EF。

我能够通过安装我的服务然后 ATTACHing 到运行进程来发现这个问题。

【讨论】:

    【解决方案2】:

    试试这些:

    将跟踪线添加到这些:

    TimerForNotification.Stop();
    
    try
    {
     int count = new GetSMSNotifications().process();
    }
    catch (Exception ex)
    {
     // trace line here with ex.ToString().
    }
    
    TimerForNotification.Start();
    // trace line here stating, i started at DateTime.Now;
    

    去掉执行权限,看看上面的代码有没有产生跟踪线。

    如果是,则会显示异常详细信息。 (即使你的方法看起来很安全)相应地修复它。

    如果捕获没有跟踪,那么您应该会看到启动后跟踪的跟踪行,这意味着服务正在按预期工作。

    【讨论】:

    • #raja 我尝试了您的建议,但发生了相同的行为。再次查看问题后,我认为它似乎挂起的原因是因为该应用程序永远不会从 .process() 返回。因此,计时器不会重新启动。 SQL 异常正在阻止计时器重新启动。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 2019-01-06
    • 1970-01-01
    相关资源
    最近更新 更多