1

I have a .NET 2.0 application. In this application, I need to pass data back to my server. The server exposes a REST-based URL that I can POST data to. When I pass data back to my server, I need to sometimes do so asynchronously, and other times I need a blocking call. In the scenario of the asynchronous call, I need to know when the call is completed. Everything up to this point I understand how to do.

Where I get into trouble is, the method that I am working on MUST be static. It's code I've inherited, and I'd rather not have to redo all of this code. Currently, I have two static methods:

public static string SendData (...) {
}

public static string SendDataAsync(...) {

}

The string returned is a response code from the server. The static part is giving me fits. It doesn't cause a problem in my blocking version. However, in the contest of the asynchronous call, I'm not sure what to do.

Does anyone have any insights they can provide?

Spontifixus
  • 6,570
  • 9
  • 45
  • 63
Bill Jones
  • 701
  • 4
  • 16
  • 24
  • 1
    Just wrap the blocking call in a delegate and use its async mechanism. – leppie Feb 11 '13 at 16:08
  • You will have to change the signature of your static method. You'll either need to return an object which will indicate when the operation is done and contain the result (i.e. IAsyncResult`), pass in a callback delegate, expose a static event, or something else. You won't be able to expose the string directly though unless you block, in which case it's not async. – Servy Feb 11 '13 at 16:29
  • @Servy can you show some code referring to what you mean? If this is what it sounds like, I'd like to give you credit for the answer. – Bill Jones Feb 11 '13 at 18:06
  • @BillJones Which you use is likely dependant on the method used by the underlying async method. If it calls a callback then just pass your callback method to the async method. If it fires an event add an event handler to that event, and if it returns an object that exposes the async result in some manor, such as IAsyncResult, then return that. – Servy Feb 11 '13 at 18:19

2 Answers2

0

Create a class wrapping your service calls. From that only call the static blocking method, but call it from a background thread. Then execute a callback or raise an event once the service call returned:

public class CompletedEventArgs : EventArgs
{
    public string Result { get; set; }
}

public class MyServiceWrapper
{
    public event EventHandler<CompletedEventArgs> CallCompleted;

    public string SendData()
    {
        return StaticService.SendData();
    }

    public void SendDataAsync()
    {
        ThreadPool.QueueUserWorkItem(state => {
            var result = StaticService.SendData();
            var handler = CallCompleted;
            if (handler != null)
            {
                handler(this, new CompletedEventArgs{ Result = result });
            }
        });
    }
}

Keep in mind though that the event that gets raised does not come from the UI-thread, thus you have to dispatch it accordingly when you want to react to it in a UI.

Spontifixus
  • 6,570
  • 9
  • 45
  • 63
0

This is the general async pattern before C# 5 (IIRC).

public static string SendData (...) {
}

public static IAsyncResult BeginSendData(..., AsyncCallback cb) {
   var f = new Func<..., string>(SendData);
   return f.BeginInvoke(..., cb, f);
}

public static string EndSendData(IAsyncResult ar) {
   return ((Func<..., string>) ar.AsyncState).EndInvoke(ar); 
}

Usage:

BeginSendData(..., ar => 
   {
     var result = EndSendData(ar);
     // do something with result
   });

Full console example:

public static string SendData(int i)
{
    // sample payload
    Thread.Sleep(i);
    return i.ToString();
}

public static IAsyncResult BeginSendData(int i, AsyncCallback cb)
{
    var f = new Func<int, string>(SendData);
    return f.BeginInvoke(i, cb, f);
}

public static string EndSendData(IAsyncResult ar)
{
    return ((Func<int, string>)ar.AsyncState).EndInvoke(ar);
}

static void Main(string[] args)
{
    BeginSendData(2000, ar => 
        {
            var result = EndSendData(ar);
            Console.WriteLine("Done: {0}", result);
        });

    Console.WriteLine("Waiting");
    Console.ReadLine();
}

The above will print:

Waiting
Done: 2000
leppie
  • 115,091
  • 17
  • 196
  • 297