views:

224

answers:

5

I have an API that I'm working with and it has limited documentation. I have been told that some of the methods that it executes are called asynchronously.

How can I get the result of these asynchronous calls. Note that I am not doing anything special to call them, the API handles the asynchronous part. But I can't seem to get a "reply" back from these calls - I'm assuming that's because they are in another thread.

UPDATE - I've included some of the code below. The API uses an event procedure for the callback but it never seems to fire.

public partial class Window1 : Window
{
    ClientAppServer newServer= new ClientAppServer();

    public Window1()
    {
        InitializeComponent();
        newServer.ReceiveRequest += ReadServerReply;
    }


    private void ReadServerReply(RemoteRequest rr)
    {

        MessageBox.Show("reading server reply");
        if ((rr.TransferObject) is Gateways)
        {
            MessageBox.Show("you have gateways!");
        }
    }


    private void login()
    {
            newServer.RetrieveCollection(typeof(Gateways), true);

    }


    private void button1_Click(object sender, RoutedEventArgs e)
    {
        this.login();
    }
A: 

You get your result from Asynchronous calls by passing a pointer to a callback function. Please let us know which API you are trying to call, and someone probably will provide you some sample code.

Black Frog
+1  A: 

Typically you would pass in a reference to a function that the method will "call back" when it is complete. For a great example of this behaviour, look at the BackgroundWorker and it's RunWorkCompleted event. This is set as a property rather than passed in as an argument, but the same idea applies.

If you have some sourcecode, or at least the name of the API you are using, we may be able to be more specific, though.

Here's a basic example of passing in the callback method as an argument:

public SearchForm : Form
{
    public void StartSearch(string searchtext)
    {
        searcher.SearchAsync(searchtext, SearchCompleted);
    }

    public void SearchCompleted(IList<SearchResult> results)
    {
        // Called by the async searcher component, possibly on another thread

        // Consider marshalling to the UI thread here if you plan to update the UI like this:
        if (InvokeRequired) 
        {
            Invoke(new Action<IList<SearchResult>>(SearchCompleted), results);
            return;
        }

        foreach (var result in Results)
        {
            AddToList(result);
        }
    }
}
Neil Barnwell
I think this answer is on the right track. I think the key is in the commented code. How would I be able to marshal it the the same thread as the UI
Jim Beam
I modified the example to assume it's working on a Form, hence the calls to Form.InvokeRequired and Form.Invoke.
Neil Barnwell
A: 

You need to use the BeginInvoke and EndInvoke methods.

This article shows how to call a method asynchronously:

http://support.microsoft.com/kb/315582

Kevin
+2  A: 

There are several ways that operations can take place asynchronously in .NET. Since you didn't post any specifics, I'll give an overview of the more common patterns:

AsyncWaitHandle

Often you'll find (especially in the .NET framework classes) pairs of methods named with Begin and End (i.e. something like BeginReceive and EndReceive).

Calling the begin function returns an AsyncWaitHandle object, which can be used to synchronize threads like a regular WaitHandle (by calling WaitOne or passing it into the static WaitHandle.WaitAny or WaitHandle.WaitAll functions), then is passed into the corresponding "end" function to obtain the return value of the function (or, if one occurred, throw the exception that was encountered).

If you use the simple .NET facility for calling a method asynchronously (creating a delegate for the function and calling BeginInvoke and EndInvoke), then this is the approach you'll need to use. However, most API's that have built-in support for asynchronous operations will handle the actual asynchronous calling part for you, leaving you with properly named BeginXXX and EndXXX functions, rather than forcing you to create a delegate yourself.

Sample using the WaitHandle:

IAsyncResult result = object.BeginOperation(args);

result.AsyncWaitHandle.WaitOne(); 
// that will cause the current thread to block until
// the operation completes. Obviously this isn't
// exactly how you'd ordinarily use an async method
// (since you're essentially forcing it to be
// synchronous this way)

returnValue = object.EndOperation(result);

Often async methods are coupled with events, as shown below.

Events

Sometimes a method call that completes asynchronously will raise an event upon its completion. This is also sometimes used in combination with the AsyncWaitHandle approach to deliver the notification that the process has completed. For example, the MSMQ libraries have a BeginReceive and EndReceieve function on the queue object, as well as a ReceieveCompleted event. When the event fires, it indicates that EndReceive can then be called, passing in the AsyncWaitHandle object returned from the call to BeginReceive. to get the actual message that was received.

Either way, you attach to the event and use it as you would any other event.

Sample using AsyncWaitHandle and events:

(somewhere in the code)

object.OperationComplete += object_OperationComplete;

(elsewhere)

IAsyncResult result = object.BeginOperation(args);

// at this point, you can either wait for the event
// to fire, or use the WaitHandle approach as shown
// in the previous example

...

void objectOperationComplete(object sender, AsyncOperationEventArgs e)
{
    returnValue = object.EndOperation(e.AsyncResult);
}

These generally work in a variety of ways...you can hold on to the IAsyncResult returned from the Begin operation yourself, but most libraries will pass that IAsyncResult object as a property on their particular EventArgs class.

It's also common to find the return value being present as a property on the EventArgs class. While using this value is fine, if the Begin operation returned an IAsyncResult, it's always a good idea to call the corresponding End function, even if the data you need is in the EventArgs. The End function is usually the way that exceptions are caught, as well.

Callbacks

A callback (in .NET) is a delegate that is supplied to the asynchronous function. Callbacks are used in more than just asynchronous functions, but in this context they're generally a delegate that you supply when calling the function that it will call when it completes.

Callbacks are similar to events (in that they're both delegate-based), though there is more of a one-to-one correlation between the method calls and the callbacks supplied.

Example using a callback:

object.BeginOperation(args, OperationComplete);

...

void OperationComplete(SomeObject results)
{
    ...
}
Adam Robinson
+1  A: 

There are several idioms for communicating asynchronous results. Based on your question, my best guess is that you're dealing with methods that accept delegates they call upon completion ("callbacks").

You have to define a method that matches the delegate type and pass it to the asynchronous method. When it finishes, it invokes your delegate, normally passing the results via one or more of the delegate's parameters.

For example, if you have this asynchronous method:

public class Foo {
    public static void DoSomethingAsynchronous(SimpleCallback simpleCallback) {

        // First this method does something asynchronous

        // Then it calls the provided delegate, passing the operation's results
        simpleCallback(true);
    }
}

// The result parameter can be much richer - it's your primary mechanism for
// passing results back to the caller.
public delegate SimpleCallback(bool result);

You would call it like this:

public static void Main(string[] args) {
    Foo.DoSomethingAsynchronous(WriteResultToConsole);
}

// Here's your SimpleCallback
public static WriteResultToConsole(bool result) {
    Console.WriteLine(result? "Success!" : "Failed!");
}
Jeff Sternal
Interesting. What if there was no callback and used an event procedure instead?
Jim Beam