2

SQLクエリからDataTable、次にDataView、最後にDataGridView.DataSourceのBindingSourceに取得されたジョブのリストを表示するDataGridViewを備えたVB.netアプリがあります。最近、セットアップにSqlNotificationRequest機能を追加したので、ユーザーBがリスト内のジョブに対してアクションを実行すると、ユーザーAがすぐに更新されます。

このMSDNの記事(http://msdn.microsoft.com/en-US/library/3ht3391b(v=vs.80).aspx)を開発の基礎として使用しましたが、問題なく動作します。問題は、ユーザーがジョブを表示するSQLクエリのパラメーター(表示された日付など)を変更したい場合に発生します。現在、新しい通知を使用して新しいSqlCommandを作成していますが、ユーザーが日付を数回(たとえば30)変更した後、データが変更されないため、通知タイムアウトが発生すると、コールバックハンドラーがEndExecuteReaderを試行したときに上記のエラーが発生します。私のコールバックハンドラーは以下のとおりです。

    Private Sub OnSalesReaderComplete(ByVal asynResult As IAsyncResult)
    ' You may not interact with the form and its contents
    ' from a different thread, and this callback procedure
    ' is all but guaranteed to be running from a different thread
    ' than the form. Therefore you cannot simply call code that 
    ' updates the UI.
    ' Instead, you must call the procedure from the form's thread.
    ' This code will use recursion to switch from the thread pool
    ' to the UI thread.
    If Me.InvokeRequired Then
        myStatus.addHistory("OnSalesReaderComplete - Background", "Sub")
        Dim switchThreads As New AsyncCallback(AddressOf Me.OnSalesReaderComplete)
        Dim args() As Object = {asynResult}
        Me.BeginInvoke(switchThreads, args)
        Exit Sub
    End If

    ' At this point, this code will run on the UI thread.
    Try
        myStatus.addHistory("OnSalesReaderComplete - UI", "Sub")
        Dim sourceText, rSalesId As String

        waitInProgressSales = False
        Trace.WriteLine(String.Format("Sales:asynResult.IsCompleted1: {0}", asynResult.IsCompleted.ToString), "SqlNotificationRequest")
        Trace.WriteLine(String.Format("Sales:asynResult.CompletedSynchronously: {0}", asynResult.CompletedSynchronously.ToString), "SqlNotificationRequest")
        Dim reader As SqlDataReader = DirectCast(asynResult.AsyncState, SqlCommand).EndExecuteReader(asynResult)
        Trace.WriteLine(String.Format("Sales:asynResult.IsCompleted2: {0}", asynResult.IsCompleted.ToString), "SqlNotificationRequest")
        Do While reader.Read
            ' Empty queue of messages.
            ' Application logic could parse
            ' the queue data to determine why things.
            'For i As Integer = 0 To reader.FieldCount - 1
            '    'Debug.WriteLine(reader(i).ToString())
            '    Console.WriteLine(reader(i).ToString)
            'Next

            Dim bytesQN As SqlBytes = reader.GetSqlBytes(reader.GetOrdinal("message_body"))
            Dim rdrXml As XmlReader = New XmlTextReader(bytesQN.Stream)
            Do While rdrXml.Read
                Select Case rdrXml.NodeType
                    Case XmlNodeType.Element
                        Select Case rdrXml.LocalName
                            Case "QueryNotification"
                                sourceText = rdrXml.GetAttribute("source")
                            Case "Message"
                                rSalesId = rdrXml.ReadElementContentAsString
                        End Select
                End Select
            Loop
        Loop

        reader.Close()


        ' The user can decide to request
        ' a new notification by
        ' checking the check box on the form.
        ' However, if the user has requested to 
        ' exit, we need to do that instead.
        If exitRequestedSales Then
            'Me.Close()
            commandSales.Notification = Nothing
        Else
            Select Case sourceText.ToLower
                Case "data"
                    Trace.WriteLine(String.Format("SalesId: {0}, data notification", rSalesId), "SqlNotificationRequest")
                    Call GetSalesData(True, action.REATTACH)
                Case "timeout"
                    'check timeout is for this user and relates to current wait thread
                    Select Case salesId = rSalesId
                        Case True
                            Trace.WriteLine(String.Format("SalesId: {0}, timeout - current", rSalesId), "SqlNotificationRequest")
                            Call GetSalesData(True, False)
                        Case False
                            Trace.WriteLine(String.Format("SalesId: {0}, timeout - old", rSalesId), "SqlNotificationRequest")
                            Me.ListenSales()
                    End Select
            End Select
        End If
    Catch ex As Exception
        Call errorHandling(ex, "OnSalesReaderComplete", "Sub")
    End Try
End Sub

問題は、通知が更新( "data")によるものであるか、タイムアウトが現在の要求に対するものである場合に、データを更新して通知要求を更新する(GetSalesDataを使用)だけであるようです。その他の通知では、アプリケーションはMe.ListenSalesを呼び出し、SQLコマンド「WAITFOR(RECEIVE * FROM [QueueMessage])」を作成し、MSDNの記事に従ってコールバックリスナーを開始します。Me.ListenSales行を削除すると、データまたは現在のクエリのタイムアウトが原因ではない通知を受信すると、アプリケーションは通知のリッスンを停止します。

他の解決策を試してみたのと同じ質問をMSDNフォーラム( http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/0f7a636d-0c9b-4b39-b341-6becf13873dc )にも投稿しました。成功するには、これが可能かどうか、可能であればどのように行うかについてのアドバイスが必要です。

4

0 に答える 0