In my previous post, I a sample “Service Agent” in VB. I will now extend the example to provide notification of results.
The form “MainForm” has now been extended to listen to a new shared event “AddReturn” on the service agent.
Public Class MainForm
Private WithEvents moManager As RequestManager = DatabaseRequestManagerIntializer.Initialize("QueueDatabase")
Private moMyCalculator As New CalculatorServiceAgent(moManager.Instance.RequestQueue)
Private Sub cmdDispatchMessages_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdDispatchMessages.Click End Sub Private Sub Main_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
AddHandler CalculatorServiceAgent.AddReturn, AddressOf OnAddReturn
End Sub
Private Sub OnAddReturn(ByVal a As Integer, ByVal b As Integer, ByVal ans As Integer)
' WARNING: Me.Invoke should be used to do UI operations as this event may not be executed on a UI thread.
MsgBox(String.Format("{0} + {1} = {2}", a, b, ans))
End Sub
End Class
The Service Agent class now “wires up” the IntegerCalculatorServiceCallback class as the “ReturnCallback”. This calls a shared method on the service agent to communicate back to the caller.
moManager.DispatchAllPendingRequests()
Private Sub cmdSubmitLocalRequest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSubmitLocalRequest.Click
moMyCalculator.Add(1, 1)
End Sub
Public Class CalculatorServiceAgent
Private moRequestQueue As IRequestQueue
Public Shared Event AddReturn(ByVal a As Integer, ByVal b As Integer, ByVal ans As Integer)
Public Sub New(ByVal requestQueue As IRequestQueue) Dim behavior As New OfflineBehavior() Dim request As New Request() request.OnlineProxyType = GetType(IntegerCalculatorServiceOnlineProxy) moRequestQueue.Enqueue(request)
End Function
Friend Shared Sub OnAddReturn(ByVal request As Request, ByVal parameters As Object(), ByVal returnValue As Integer) End Class
The “business logic” is unchanged.
moRequestQueue = requestQueue
End Sub
''' <summary>
''' Enqueues a request to the <c>Add</c> web service method through the agent.
''' </summary>
''' <returns>The unique identifier associated with the request that was enqueued.</returns>
Public Function Add(ByVal a As Int32, ByVal b As Int32) As Guid
behavior.ProxyFactoryType = GetType(ObjectProxyFactory)
behavior.MaxRetries = 1
behavior.Stamps = 1
behavior.Expiration = DateTime.Now + New TimeSpan(0, 0, 30)
behavior.ReturnCallback = New CommandCallback(GetType(IntegerCalculatorServiceCallback), "OnAddReturn") ' If it works, make a call back here
request.MethodName = "Add"
request.Behavior = behavior
request.CallParameters = New Object() {a, b}
request.Endpoint = "" ' Setting this to blank is important. If sent to nothing it wont work
RaiseEvent AddReturn(parameters(0), parameters(1), returnValue)
End Sub
''' <summary>
''' This class is used as a mechanism to inform the caller when a request has been completed
''' </summary>
Public Class IntegerCalculatorServiceCallback
Public Sub OnAddReturn(ByVal request As Request, ByVal parameters As Object(), ByVal returnValue As Integer)
CalculatorServiceAgent.OnAddReturn(request, parameters, returnValue)
End Sub
End Class
''' <summary> ' This could be a call out to a 3rd party component End Function
''' The proxy class is used to invoke the "real" business logic that does the work
''' </summary>
Public Class IntegerCalculatorServiceOnlineProxy
Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
Return a + b
End Class
The use of a shared event on the ServiceAgent itself is unique to my example. (for clarity) The Patterns and Practices example handles this differently.
To create events for exceptions, populate the “ExceptionCallback” property on the request object.
Going Further
I’m now considering creating a ServiceAgentBase that will make the callback events generic. I’ll let you know how it goes.