Search:
Locator+ Code:
FTPOnline Channels Conferences Resources Hot Topics Partner Sites Magazines About FTP RSS 2.0 Feed

Back to VSLive! Show Daily Home


Avoid This Web Services Gotcha
This simple Windows Forms code makes your asynchronous callbacks work the right way.
by Chris Kinsman

VSLive! SF, Day 2, February 13, 2002 — When they first use Web Services, many developers begin to think of innovative ways to use them in an asynchronous fashion. There is one big "gotcha," however, that most developers will hit the first time they try this. When using with Web Services, you have to realize that when code is executing in your callback, you are likely to be on a different thread than your user interface code.

The Windows Forms classes are all single-threaded. They expect to be accessed by the same thread that created them. A control has a couple of thread-safe methods and properties, which you can use to determine whether you need a special technique to access the control from the current thread. If the InvokeRequired property returns false, it is safe to call any methods or properties on the control. If it returns true, you must use the Invoke() method of the control to call a delegate on the control's thread. This listing shows a simple Windows Forms application that calls a Web Service that returns order data from Nwind. The service is called asynchronously and a callback is used to populate the grid. Note the use of Invoke Required and Invoke to jump thread contexts:

    Public Delegate Sub SetData(ByVal ar As _
        IAsyncResult)

    Private Sub Form1_Load(ByVal sender As _
        System.Object, ByVal e As _
        System.EventArgs) Handles MyBase.Load
        Dim oOrders As New localhost.Orders()

        ' Create the callback to pass to the 
        ' asynchronous invocation
        Dim wscb As New AsyncCallback( _
            AddressOf WebServiceCallback)
        '  Call the web method asynchronously 
        '  passing in the callback and the 
        '  service itself
        oOrders.BeginGetAllOrders(wscb, oOrders)
    End Sub

    Public Sub SetDataInGrid(ByVal ar _
        As IAsyncResult)
        Dim oOrders As localhost.Orders

        ' Grab the web service out of the async 
        ' result object AsyncState property
        oOrders = ar.AsyncState
        ' Get the data out of the finished web 
        ' service
        Dim ds As DataSet = _
            oOrders.EndGetAllOrders(ar)

        ' Put the data into the grid
        DataGrid1.DataMember = "Orders"
        DataGrid1.DataSource = ds
    End Sub

    Public Sub WebServiceCallback(ByVal ar As _
        IAsyncResult)
        ' When this callback executes we are on a 
        ' different thread than the grid
        ' Windows Forms is single threaded so we 
        ' need to call invoke to cross threads
        Dim dlg As New SetData(AddressOf _
            SetDataInGrid)
        DataGrid1.Invoke(dlg, New Object() {ar})
    End Sub

About the Author
Chris Kinsman is an instructor with Deep Training. He teaches courses on ASP.NET in both VB.NET and C#. In a previous life Chris was the CTO for a large scale Web site. Chris is a contributing editor for Visual Studio Magazine and is currently working on an ASP.NET book for SAMS. Chris is not a full-time speaker; most of his time is spent doing consulting with Vergent Software. He can be reached at: ckinsman@vergentsoftware.com.

Back to top





Java Pro | .NET Magazine | Visual Studio Magazine | XML & Web Services Magazine
VSLive! | Thunder Lizard Events | Discussions | Newsletters | FTP Home