-1

I am having trouble understanding how asynccallbacks work. I have a method in a separate class (call this class "Foo") that requires me to pass in an asynccallback method and an object.

This method is supposed to download some content as a string.

public void sampleFunction(AsyncCallback callback, object x)
{
    //download some content as a string
}

Then I have my asynccallback method and my method from where I call the above method:

public static void test(IAsyncResult result)
{
     Console.WriteLine("Reached");

     //Is result the string that should have been downloaded? Confused
     Console.WriteLine(result); 
}

public static void sampleFunction2()
{
    Foo z;
    object t = "hello";
    AsyncCallback callback = new AsyncCallback(test);
    z.sampleFunction(callback, t);
 }

After calling sampleFunction2, nothing prints to the console. What am I doing/understanding wrong?

TaW
  • 53,122
  • 8
  • 69
  • 111
SKLAK
  • 3,825
  • 9
  • 33
  • 57
  • What is the type of `result`? – Mr Lister Aug 14 '15 at 17:58
  • @SKLAK if you are not sure about how async works then do a google search also read the posted answers here for explanation http://stackoverflow.com/questions/24953808/write-your-own-async-method – MethodMan Aug 14 '15 at 17:59
  • @MrLister It is some interface which just contains one method that cancels the asynchronous operation. – SKLAK Aug 14 '15 at 18:00
  • What does the debugger tell you if you set a breakpoint on the first call to `Console.WriteLine`? What does the documentation tell you about `IAsynchResult`? – Ken White Aug 14 '15 at 18:00
  • @KenWhite It doesn't even reach the breakpoint so the method isn't being reached – SKLAK Aug 14 '15 at 18:03
  • @SKLAK What are the real method names. You've destroyed the `begin`/`end` method pattern and it is not clear with method is in the same class as which method. – Aron Aug 14 '15 at 18:05
  • Of course not nobody is calling the test function – Philip Stuyck Aug 14 '15 at 18:05
  • An asynccallback is a callback that will be called when an asynchronous operation finishes. It is typically passed as a parameter to a method whose name begins with begin. Or you use a delegate and do an begininvoke. – Philip Stuyck Aug 14 '15 at 18:06
  • Think things through. If the breakpoint isn't being reached, it means the function isn't being called. So where do you logically think you should be calling back with a callback function? Perhaps in the function that receives a `callback` as a parameter? – Ken White Aug 14 '15 at 18:09
  • @KenWhite I thought test would get called once the asynchronous operation (in this case sampleFunction) finishes? – SKLAK Aug 14 '15 at 18:10

3 Answers3

2

I would use async await keywords instead of older (but still valid) method which uses AsyncCallback.

public async Task SampleFunction(object x)
{
    await DownloadAsync(); //Download your string using await
    //await will block here until "DownloadAsync" returns. It will return control to the calling method and return here when the await finishes (or comes back to finish the method).
}

public async static CallerMethod()
{
    await SampleFunction(yourObject);
    //The code will continue here while the string is downloading and it will pause the execution to finish the callback (after the await) anytime.
}

Think of an async method as a two part method. First the logic and the callback (code after the await statement).

Hope this is not too hard to understand, I can clarify or reformulate if needed.

Philippe Paré
  • 4,279
  • 5
  • 36
  • 56
1

An asynccallback is a callback that will be called when an asynchronous operation finishes. It is typically passed as a parameter to a method whose name begins with begin. Or you use a delegate and do an begininvoke

The whole process is explained by microsoft in detail here :https://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110).aspx

Look for the last example in the link I provided.

Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
  • Wouldn't test get called once sampleFunction finishes? – SKLAK Aug 14 '15 at 18:09
  • Of course not, it would be called if you have a delegate towards that method and then do a begininvoke and then pass the callback. Read the last example in the link I provided it does exactly what you want to do. – Philip Stuyck Aug 14 '15 at 18:10
  • I see, so what happens to the string that's supposed to be downloaded by sampleFunction? – SKLAK Aug 14 '15 at 18:11
  • it should be the returnvalue of the testmethod. Then using endinvoke you get to the result. – Philip Stuyck Aug 14 '15 at 18:15
0

I am almost 100% sure you have completely bastardized the naming convention using in sampleFunction1 and sampleFunction2

I am sure you meant.

public class Foo
{
    public void BeginSampleFunction(AsyncCallback callback, object x)
    {
         //download some content as a string
    }

    public string EndSampleFunction(IAsyncResult result)
    {
         //download some content as a string
    }
}

The test code should be

public void Test()
{
    AsyncCallback callback = a =>
    {
        string result = foo.EndSampleFunction(a);
        Console.WriteLine(result);
    }
    object state = null;
    foo.BeginSampleFunction(callback, state);
}

This pattern is called the Asynchronous Programming Model (APM). It is completely deprecated, and should not be used. Today we use Task Asynchronous Programming (TAP).

In TPL there is a factory method for converting methods from APM to TAP.

public async Task Test()
{
    Task<string> task = Task.Factory.FromAsync(foo.BeginSampleFunction, foo.EndSampleFunction, null);
    string result = await task;
    Console.WriteLine(result);
}
Aron
  • 15,464
  • 3
  • 31
  • 64
  • Sorry about that.. Very new to this. Thanks for the fix – SKLAK Aug 14 '15 at 18:13
  • And where would the callback be called ? If you do foo.BeginSampleFunction you are passing parameters to a function doing nothing. Nobody is calling the callback. this will not work. You need a delegate and to an begininvoke on the delegate. – Philip Stuyck Aug 14 '15 at 18:13
  • @PhilipStuyck The point of passing a callback into the `BeginXXX` method is that when it completes, it will call the callback. There is no delegate to call the `BeginInvoke` on. This is NOT THREADING. THIS IS ASYNCHRONOUS I/O. – Aron Aug 14 '15 at 18:15
  • @SKLAK I've edited to show you the more modern approach to using APM based methods, which are deprecated. But if the class also contains a `SampleMethodTaskAsync` use that instead. – Aron Aug 14 '15 at 18:16
  • The point is that your answer is wrong. Beginblabla is supposed to do something on a background thread, and the callback is called when it completes. Using your code there is no background thread. And you would have to call the callback yourself. Take a look at the link I provided, it shows the right way to do it. – Philip Stuyck Aug 14 '15 at 18:17
  • @Aron I'll check out the more modern approach as well. Thanks – SKLAK Aug 14 '15 at 18:19
  • @PhilipStuyck No it is not. Given that you are a C++ programmer I would imagine you would understand the concepts of I/O interrupts much better than this. THERE IS NO THREAD. The BeginXXX method runs on the current thread, invokes I/O which then has a ...oh...you are sooo confused with `Control.BeginInvoke` for marshelling to the UI Thread...Face Palm – Aron Aug 14 '15 at 18:20
  • I am not confused, you are. Read the link I provided the whole point of any method that starts with begin is to do something on a background thread. You are passing a callback for when the asynchronous operation on the other thread is finished. There is also no need to insult me. – Philip Stuyck Aug 14 '15 at 18:22
  • @PhilipStuyck I am not trying to insult you. But you are referencing code that IS about threading. The OP said that his class exposes the `IAsyncResult` directly. Please could you take a look at the Asynchronous Programming Model. Your link is about taking a `Delegate` and transforming it into a APM method pair. Which is not needed, as the class already exposes the APM pair. – Aron Aug 14 '15 at 18:25
  • https://msdn.microsoft.com/en-us/library/system.io.stream.beginread(v=vs.110).aspx asynchronous means it will be executed on a different thread. By giving your method name the beginning letters begin does not make it happen. – Philip Stuyck Aug 14 '15 at 18:25
  • The point is that he wants the method sampleFunction to be called asynchronously. – Philip Stuyck Aug 14 '15 at 18:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/87026/discussion-between-aron-and-philip-stuyck). – Aron Aug 14 '15 at 18:27
  • This approach ended up working.. All the answers are valuable though but I'll mark this one as correct – SKLAK Aug 14 '15 at 18:31
  • Aron was right btw, we had a small chat and came to the conclusion that he is right. So I ended up learning something ;-) – Philip Stuyck Aug 14 '15 at 18:54