从System.Timers.Timer回调调用时,ASMX“页面方法”获取NullReferenceException

时间:2014-07-25 15:07:12

标签: asp.net vb.net timer oledb asmx

我有一个数据库调用需要每小时进行一次,并且已经实现了System.Timers.Timer类来执行调用。问题是,一旦计时器完成并执行其回调(无论是2分钟还是1小时),系统拒绝打开数据库连接,引用对象引用未设置为对象错误的实例,尽管首次通过Web服务调用方法时,或者在需要DB并且可以访问它的任何其他站点函数下,数据库连接方法正常工作。

计时器运行时我的课程是否被垃圾收集?

我的IIS配置中是否缺少特定设置以允许Timer回调事件在没有用户特定输入的情况下打开数据库连接?

我是否疯了,自动每小时数据库调用执行不力?

仅供参考,该网站是作为代码隐藏运行时编译站点实现的。

Public Shared noticeTimer As Timer

<WebMethod()> _
    Public Shared Function GetOpenDegrades()
    Dim dbCon As OleDbConnection = DbConnection()
    Dim sql As String = "SELECT XYZ"
    'Init sql command
    Dim cmd As New OleDbCommand(sql, dbCon)
    'Execute query
    Dim rdr As OleDbDataReader = cmd.ExecuteReader()
    'Add query results to list
    If rdr.HasRows Then
        While rdr.Read()
            .........
        End While
    End If
    rdr.Close()
    dbCon.Close()

    System.Threading.Thread.Sleep(5000)

    If (noticeTimer Is Nothing) Then
        noticeTimer = New Timer()   
        noticeTimer.Interval = 120000   '2 mins for testing 1 hour for production 
        noticeTimer.enabled = True
        noticeTimer.AutoReset = True
        AddHandler noticeTimer.Elapsed, AddressOf GetOpenDegrades   
    Else
        'Timer Adjustment if required
        ........
    End If
End Function

//db connection helper function
Public Shared Function DbConnection() As OleDbConnection
    Dim path As String = System.Web.HttpContext.Current.Server.MapPath("..\db\db.accdb")
    Dim dbCon As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+ path)
    dbCon.Open()
    Return dbCon
End Function

1 个答案:

答案 0 :(得分:1)

您的代码有很多问题:

  1. WebMethods不应该是Shared。事实上,我很惊讶它可以作为一个Web服务操作。
  2. 在ASMX Web服务中,就像使用ASP.NET页面一样,所有用户都共享Shared个资源。
  3. 您不应在Web服务中执行后台任务。它们应该在一个单独的Windows服务中执行,在这种情况下,它可以在计时器到期时简单地调用Web服务。
  4. 如果您决定忽略最后一条建议,至少不要让回调方法与WebMethod相同。如果你这样做,那么将从两个不同的上下文调用WebMethod - 一次是在发出实际的Web服务请求时,另一次是在超时到期时。在后一种情况下,将没有请求上下文。
  5. 您的问题与您正在进行数据库调用无关。只是你的坏代码碰巧正在进行数据库调用。无论你在web方法中做了什么,这种技术都可能会失败。
  6. 您的代码会创建实现IDisposable接口的各种对象。这些应该在Using块内创建和使用:

    Dim sql As String = "SELECT XYZ"
    'Init sql command
    
    Using dbCon As OleDbConnection = DbConnection()
        Using cmd As New OleDbCommand(sql, dbCon)
        'Execute query
            Using rdr As OleDbDataReader = cmd.ExecuteReader()
                'Add query results to list
                If rdr.HasRows Then
                    While rdr.Read()
                        .........
                    End While
                End If
            End Using
        End Using
    End Using
    ' Don't need the Close calls since the end of the Using blocks will do that