3

This is a C# question although the code is written using Xamarin iOS. I would like to find out how I can combine a Task method with an async function and callback delegate. So in the code sample below I would like to call await ExecuteGetAsync() and wait until SendAsynchronousRequest() completes.

private async Task<CustomHttpResponse> ExecuteGetAsync(CustomHttpRequest inRequest)
{
    NSUrlConnection
        .SendAsynchronousRequest(
            (NSUrlRequest)request,
            NSOperationQueue.MainQueue,
            delegate(NSUrlResponse inResponse, NSData inData, NSError inError)
            {
                // Return the response somehow
            });
}
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
checkmate711
  • 3,301
  • 2
  • 35
  • 45
  • 1
    MSDN has [an article](https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110).aspx) on converting one asynchronous pattern to another. – chris Dec 09 '15 at 19:09

2 Answers2

4

You should use the TaskCompletionSource class like this:

private Task<CustomHttpResponse> ExecuteGetAsync(CustomHttpRequest inRequest)
{
    var tcs = new TaskCompletionSource<CustomHttpResponse>();

    NSUrlConnection
        .SendAsynchronousRequest(
            (NSUrlRequest)request, //shouldn't this be inRequest?
            NSOperationQueue.MainQueue,
            delegate(NSUrlResponse inResponse, NSData inData, NSError inError)
            {
                bool error = ... //determine if we have an error

                if(error)
                    tcs.SetException(new Exception(".. error message here ..")); //if we have an error, use the SetException method to set the exception for the Task
                else
                {
                    CustomHttpResponse result = ... // if we don't have an error, get result
                    tcs.SetResult(result); //set the result
                }
            });

    return tcs.Task;
}

Please note that the method no longer uses the async keyword.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
-1

Because you have access to the parent scope, you can define your result variable up front. Then, create a wait handle. When your code gets the final response you set the result and the handle and your code returns the result in the main scope.

private async Task<CustomHttpResponse> ExecuteGetAsync(CustomHttpRequest inRequest)
{
    CustomHttpResponse result = null; // Put initial result here.
    var handle = new AutoResetEvent(false);
    NSUrlConnection
        .SendAsynchronousRequest(
            (NSUrlRequest)request,
            NSOperationQueue.MainQueue,
            delegate(NSUrlResponse inResponse, NSData inData, NSError inError)
            {
                // Return the response somehow
                result = // make your result
                handle.Set();
            });

    handle.WaitOne(10000) // Wait up to 10 seconds for result
    return result;
}
The Sharp Ninja
  • 1,041
  • 9
  • 18