Raising an Event in a Delegate causes problems

J

Jon Turner

I have an asynchronous call to a remote procedure that is invoked thru
BeginInvoke. The problem is that in the Delegate if I throw an event
before the CallBack function exits, the CallBack will get called multiple
times and error out with the following Error:

<EndInvoke can only be called once for each asynchronous operation.>

If I comment out the RaiseEvent, then the Callback exits with a single call
to EndDelegate.

Question: How can I throw an Event in the CallBack without causing a
problem
in the CallBack.

Many Thanks In Advance


'************************* Sample Code Snippet ****************************

Private Sub DataCallback(ByVal result As IAsyncResult)

Dim objResult As AsyncResult = CType(result, AsyncResult)


Dim objDelegate As FooDelegate = _
CType(objResult.AsyncDelegate, FooDelegate)

Dim bStatus As Boolean
Dim sFooData As String


bStatus = objDelegate.EndInvoke(sFooData, result)
m_checkList.Item(sCheckID).PCLStream = sPCLData
m_checkList.Item(sCheckID).Completed = True
m_checkList.Item(sCheckID).Errors = sErrorMsg
objDelegate = Nothing
RaiseEvent FooReceived(sFooData) '<<======= Causes DataCallBack
to be recalled 5 times
Debug.WriteLine("Result is <{0}>", bStatus.ToString)
End Sub
 
J

Jon Turner

Sunny said:
Hi Jon,

can you post a complete working sample. I can not see any problem here.

Here is the complete code. The problem is in the CreateCheckPCLDelegate
function. When the event is thrown the callback
is reentered over and over again, up to about 4 times before the error
message appears.

'***************************************************************************
******************************************

Class CheckPrintDelegate

Private Const CHECKPRINT_SERVER As String =
"http://localhost/PrintServices/CheckPrintServicesFBOD.rem"
Delegate Function CreateCheckPCLDelegate(ByRef CheckID As String, ByVal
XOffSet As Integer, ByVal YOffSet As Integer, ByRef PCLStream As Byte(),
ByRef ErrorMessage As String) As Boolean

Private m_xOffSet As Integer
Private m_yOffset As Integer
Private m_sRemoteURL As String
Private m_checkList As New CheckQueueList

Public Event CheckReceived(ByVal CheckID As String)


Private Sub New()

End Sub

Public Sub New(ByVal sRemoteURL As String)

Dim properties As New Hashtable
properties("name") = "HttpBinary"

m_sRemoteURL = sRemoteURL

Try
ChannelServices.RegisterChannel(New HttpChannel(properties, New
BinaryClientFormatterSinkProvider, Nothing))
' The last parameter above (Nothing) is the server sink provider
chain
' to obtain the default behavior (which includes SOAP and
' binary formatters on the server side).
Catch er As System.Runtime.Remoting.RemotingException
If er.Message.IndexOf("already registered") < 0 Then
Throw New ApplicationException(er.Message)
End If

Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try

End Sub

Public Property XOffset() As Integer
Get
Return (m_xOffSet)
End Get
Set(ByVal Value As Integer)
m_xOffSet = Value
End Set

End Property

Public Property YOffset() As Integer
Get
Return (m_yOffset)
End Get
Set(ByVal Value As Integer)
m_yOffset = Value
End Set

End Property

Public Sub ClearList()
m_checkList.Clear()
End Sub

Public ReadOnly Property CheckList() As CheckQueueList
Get
CheckList = m_checkList
End Get
End Property

Public Function GetDeclineLetterTemplate(ByRef sData As Byte(), ByRef
ErrorMessage As String) As Boolean

Dim objCheckPrintServices As LTSWebChecks.CheckPrintServicesFBOD
Dim bStatus As Boolean
Dim sStream As String

Try
objCheckPrintServices =
CType(Activator.GetObject(GetType(LTSWebChecks.CheckPrintServicesFBOD),
m_sRemoteURL), LTSWebChecks.CheckPrintServicesFBOD)
bStatus = objCheckPrintServices.GetDeclineLetterTemplate(sData,
ErrorMessage)
Catch ex As Exception
Debug.Write(ex.Message)
Throw New ApplicationException("GetDeclineLetterTemplate():" &
ex.Message)
End Try

GetDeclineLetterTemplate = bStatus

End Function

Private Sub CreateCheckPCLCallback(ByVal result As IAsyncResult)

Dim objResult As AsyncResult = CType(result, AsyncResult)
Debug.WriteLine("AsyncResult = " & objResult.IsCompleted.ToString)


Dim objDelegate As CreateCheckPCLDelegate = _
CType(objResult.AsyncDelegate, CreateCheckPCLDelegate)

Dim bStatus As Boolean
Dim sPCLData As Byte()
Dim sCheckID As String
Dim sErrorMsg As String


bStatus = objDelegate.EndInvoke(sCheckID, sPCLData, sErrorMsg,
result)
m_checkList.Item(sCheckID).PCLStream = sPCLData
m_checkList.Item(sCheckID).Completed = True
m_checkList.Item(sCheckID).Errors = sErrorMsg
objDelegate = Nothing
RaiseEvent CheckReceived(sCheckID) '<<<========= Problem
is Here
Debug.WriteLine("Result is <{0}>", bStatus.ToString)
End Sub

Public Function GetMICRFont(ByRef sPCLStream As Byte()) As Boolean

Dim objCheckPrintServices As LTSWebChecks.CheckPrintServicesFBOD
Dim bStatus As Boolean

Try
objCheckPrintServices =
CType(Activator.GetObject(GetType(LTSWebChecks.CheckPrintServicesFBOD),
m_sRemoteURL), LTSWebChecks.CheckPrintServicesFBOD)
bStatus =
objCheckPrintServices.CreateMICRFontPCLStream(sPCLStream)
Catch ex As Exception
Debug.Write(ex.Message)
Throw New ApplicationException("GetMICRFont():" & ex.Message)
End Try

GetMICRFont = bStatus

End Function
Public Function GetTestPCLStream(ByVal CheckID As String, ByRef
sPCLStream As Byte(), ByRef sErrorMessage As String) As Boolean

Dim objCheckPrintServices As LTSWebChecks.CheckPrintServicesFBOD
Dim bStatus As Boolean

Try
objCheckPrintServices =
CType(Activator.GetObject(GetType(LTSWebChecks.CheckPrintServicesFBOD),
m_sRemoteURL), LTSWebChecks.CheckPrintServicesFBOD)
bStatus =
objCheckPrintServices.CreateTestCheckPCLStream(CheckID, m_xOffSet,
m_yOffset, sPCLStream, sErrorMessage)
Catch ex As Exception
Debug.Write(ex.Message)
Throw New ApplicationException("GetTestPCLStream():" &
ex.Message)
End Try

GetTestPCLStream = bStatus

End Function

Public Function GetPCLStream(ByVal CheckID As String, ByRef sPCLStream
As Byte(), ByRef sErrorMessage As String) As Boolean

Dim objCheckPrintServices As LTSWebChecks.CheckPrintServicesFBOD
Dim bStatus As Boolean

Try
objCheckPrintServices =
CType(Activator.GetObject(GetType(LTSWebChecks.CheckPrintServicesFBOD),
m_sRemoteURL), LTSWebChecks.CheckPrintServicesFBOD)
bStatus = objCheckPrintServices.CreateCheckPCLStream(CheckID,
m_xOffSet, m_yOffset, sPCLStream, sErrorMessage)
Catch ex As Exception
Debug.Write(ex.Message)
Throw New ApplicationException("GetPCLStream():" & ex.Message)
End Try

Return (bStatus)

End Function

Public Sub QueuePCLStream(ByVal CheckID As String)

Dim objCallback As New AsyncCallback(AddressOf
CreateCheckPCLCallback)
Dim objCheckPrintServices As LTSWebChecks.CheckPrintServicesFBOD
Dim result As IAsyncResult
Dim sPCLStream As Byte()
Dim sErrorMsg As String

Try
objCheckPrintServices =
CType(Activator.GetObject(GetType(LTSWebChecks.CheckPrintServicesFBOD),
m_sRemoteURL), LTSWebChecks.CheckPrintServicesFBOD)
Dim objDelegate As New CreateCheckPCLDelegate( _
AddressOf objCheckPrintServices.CreateTestCheckPCLStream)
'For Debuggin, Change from Test
m_checkList.Add(CheckID, Nothing, Nothing, False)
result = objDelegate.BeginInvoke(CheckID, m_xOffSet, m_yOffset,
sPCLStream, sErrorMsg, objCallback, _
Nothing)
'm_checkList.Add(CheckID, Nothing, Nothing, False)
Catch ex As Exception
Debug.Write(ex.Message)
Throw New ApplicationException("QueuePCLStream():" & ex.Message)
End Try

End Sub

Public Function GetQueuedCheckData(ByVal checkID As String) As
CheckQueueItem
'Note: This is a Volatile Get Function. It will return the
CheckQueueItem
' and then remove it from the list

GetQueuedCheckData = m_checkList.Item(checkID)
m_checkList.Remove(checkID)

End Function

End Class
 
S

Sunny

Hi Jon,
as I'm c# guy, may I ask you to strip your code as much as possible. Leave
actually only the minimum number of methods and properties which reproduce
the problem.

Thanks
Sunny
 
Top