0

I have a console app that executes a class method (in a different project). This method performs a POST to a webservice asynchronously (this is a lengthy operations of 3 minutes) and has a callback that returns the number of records affected by the POST. In the meantime the program continues doing other things that takes less than 3 minutes and the program exits before the callback returns.

In the past I have used a ManualResetEvent as depicted below to prevent completion but in this case my method is in a different class library that I would like to keep as clean as possible.


static ManualResetEvent resetEvent = new ManualResetEvent(false)

static void Main()
{
     CallAsyncMethod();
     // Do other things...
     resetEvent.WaitOne(); // Blocks until "set"
}

void AsyncMethodCallback()
{
     // Do processing on completion...
     resetEvent.Set(); // Allow the program to exit
}

I would appreciate any help in coming up with a clean pattern to accomplish this without polluting the called class with execution flags.

Diego
  • 998
  • 1
  • 11
  • 20

2 Answers2

5

If you can (in particular, if you're using .NET 4), make your CallAsyncMethod return a Task or Task<T>. Then you can easily attach a continuation, wait for it to complete etc. If the only purpose of the callback is to get the number of records, returning a Task<int> would be ideal. You can use TaskCompletionSource<TResult> so populate the result really easily within the async method, so you don't need the callback at all within your main class, which would have a main method something like:

static void Main()
{
     Task<int> asyncTask = CallAsyncMethod();
     // Do other things...
     int count = asyncTask.Result;
     // Do anything you need with the count
}

The new async features in C# 5 are designed to work well with Task<T>, so you'll be all ready to embrace the new version when it arrives.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon Skeet: Do [ContinueWith](http://msdn.microsoft.com/en-us/library/dd270696.aspx) is guaranteed to be executed? I mean if the calling thread is going to dead (in this case a main thread) will it wait, as there is a yet a `Task<>` that has to execute a stuff on completion? – Tigran Apr 17 '12 at 20:08
  • @Tigran: In what sense? Before the app shuts down? Not if there aren't any foreground threads, IIRC. But here you wouldn't need ContinueWith - just wait for the task to complete. – Jon Skeet Apr 17 '12 at 20:10
  • @Tigran: Now you've edited the comment :) No, if the Main method returns and there are no other foreground threads, I wouldn't expect the continuation to fire. But it's easy to stop the main method from returning - see my edit. – Jon Skeet Apr 17 '12 at 20:11
  • ah ok, so it's just *subscription to completion "event"*, as I was thinking about. Thanks. – Tigran Apr 17 '12 at 20:11
  • Thanks Jon. Funny thing, I was just browsing your book for a possible answer. I wanted to avoid returning a Task but in retrospect it does seem the cleanest solution. Thanks for the quick response. – Diego Apr 17 '12 at 20:13
1

Start webservice request on another foreground thread. Application will not exit until all foreground threads completes execution.

new Thread(() => CallSynchronousMethod()).Start();
Ňuf
  • 6,027
  • 2
  • 23
  • 26