Monthly Archives: September 2007

Return Callbacks and the Disconnected Service Agent

Standard

 

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
    moManager.DispatchAllPendingRequests()

End Sub
Private Sub cmdSubmitLocalRequest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSubmitLocalRequest.Click
    moMyCalculator.Add(1, 1)
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. 

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)
        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

        Dim behavior As New OfflineBehavior()
        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

        Dim request As New Request()
        request.MethodName = "Add"
        request.Behavior = behavior
        request.CallParameters = New Object() {a, b}

        request.OnlineProxyType = GetType(IntegerCalculatorServiceOnlineProxy)
        request.Endpoint = ""  ' Setting this to blank is important.  If sent to nothing it wont work

        moRequestQueue.Enqueue(request)

    End Function

    Friend Shared Sub OnAddReturn(ByVal request As Request, ByVal parameters As Object(), ByVal returnValue As Integer)
        RaiseEvent AddReturn(parameters(0), parameters(1), returnValue)
    End Sub

End Class
''' <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

The “business logic” is unchanged.

''' <summary>
''' 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

        ' This could be a call out to a 3rd party component
        Return a + b

    End Function
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. 

Links

A Simple Example of a Disconnected Service Agent in VB

Standard

 

In my previous post, I introduced the “Disconnected Application Block”, which is part of the Smart Client Software Factory.   As I stated earlier, I think this provides a powerful way of implementing “Store and Forward” for both desktop and mobile applications.

In this post, I’ve provided a simple example example in VB of a form, service agent and dummy business component which is a bit simpler than the “Quickstarts.DisconnectedAgent” example it is based on.

The form “MainForm” has a command button for submitting requests and another command button for dispatching (running) the queued requests (depending on if the network is available or not).

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
        moManager.DispatchAllPendingRequests()
    End Sub

    Private Sub cmdSubmitLocalRequest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSubmitLocalRequest.Click
        moMyCalculator.Add(1, 1)
    End Sub

End Class

 

The Service Agent class contains the logic for queuing the request.

The code in the Add method creates a “behaviour” object to determine how the message should behaving in a queuing situation.  It is then used to create a request, which is placed on the “Request Queue”.

This example differs from those provided in the QuickStart in that it uses the “ObjectProxyFactory”.  This factory allows me to invoke a real object instead of a Web Service.   In this case IntegerCalculatorOnlineServiceProxy.

Public Class CalculatorServiceAgent

    Private moRequestQueue As IRequestQueue

   

    Public Sub New(ByVal requestQueue As IRequestQueue)
        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

        Dim behavior As New OfflineBehavior()
        behavior.ProxyFactoryType = GetType(ObjectProxyFactory)
        behavior.MaxRetries = 1
        behavior.Stamps = 1
        behavior.Expiration = DateTime.Now + New TimeSpan(0, 0, 30)
        

        Dim request As New Request()
        request.MethodName = "Add"
        request.Behavior = behavior
        request.CallParameters = New Object() {a, b}

        request.OnlineProxyType = GetType(IntegerCalculatorServiceOnlineProxy)
        request.Endpoint = ""  ' Setting this to blank is important.  If sent to nothing it wont work

        moRequestQueue.Enqueue(request)

    End Function

 

End Class

 

And finally, the business logic:

''' <summary>
''' 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

        ' This could be a call out to a 3rd party component
        Return a + b

    End Function
End Class

This is nice, but what if I want my code to be informed of the result? 

This will be covered in the next post.

Hidden Treasure : The Disconnected Service Agent Application Block

Standard

 

image

Currently I am designing casually connected (offline) solutions for both desktop applications and Windows Mobile.

Store and Forward

Part of the solution requires that requests can be submitted and queued for execution when the network (or the resource you’re being disconnected from) is available.  This has traditionally been known as “Store and Forward”.  These mechanisms can be seen in every day desktop applications such as Microsoft Outlook or in traditional enterprise products such as MSMQ.

As a product developer, customers have an expectation that the product works immediately, “out of the box”, with few dependencies and little configuration.  The difficulty with using MSMQ is that it can be problematic to setup.

To address the simpler “Store and Forward” requirement, the Patterns and Practices team created the original “Smart Client Offline Application Block“.    Recently I spent a great deal of time learning and converting this to .net 2.0, only to discover that it has been superceded (somewhat) by the “Disconnected Service Agent Application Block”.

Disconnected Service Agent Application Block

This is a nicer (in my opinion) implementation of the original OAB which is part of both the Smart Client Software Factory and the Mobile Smart Client Software Factory.  It uses the latest version of the Enterprise Library and seems easier to use.  Annoyingly the guidance and recipes provided only seem to work if you’re creating a CAB (Composite Application Block) application, but the Quickstarts make up for this.

It appeals to me as I can use the same solution in both desktop and mobile applications.

Dependencies

By default the application block is dependent on SQL Server CE.  This may have licensing implications.  Fortunately this is abstracted away behind the IRequestQueue interface, which isn’t too hard to implement.  I’m not sure which way I personally will go yet.

Interestingly it has generic proxies to invoke both WCF and traditional Web Services, “Out of the Box”.

So how do I get it?

The Disconnected Service Agent Application Block is only available as part of the download of the Smart Client Software Factory.  The main point of this software factory seems to be as a vehicle for CAB.  (read about it’s future here)   Interestingly DSAAB is independent of CAB.  (That’s the way I may use it). 

Currently it’s only downloadable on it’s own.

Orcas Sync Services

Visual Studio 2008 contains a sophisticated online/offline solution called “Sync Services”.  Currently it seems to me this is only oriented toward database synchronization, which is a different solution to the one DSAAB covers.  Take a look at Nick Randolph’s blog entries on this here

The code of the libraries is quite simple regardless, so I think the solution will continue to work for a long time to come.

What else?

I’ll post some simple code samples of using DSAAB using VB in future posts.

Links

Scribd

Standard

image

Now and then you come across something special, something quite profound.

I usually resist the temptation to use this blog as a “link factory”, but I found another website that I just have to post about.

The website I’m refering to is “Scribd”.  Someone described it as doing for documents what Flickr did for photos.   

There are many thousands of documents on lots of different topics.  Mostly it’s rubbish, but there are some gems.

  What I find very interesting and cool about it however is the ability to download an mp3 computer-read version of the text.  This is generated using some sort of batch program on their servers.  It’s using a pretty good voice (in my opinion) as well.  Quite listenable.  (There’s even an online player)

I am always on the lookout for things to play on my Pocket PC whilst riding my bike, so I found it useful.

Links

Scribd – The Site