Let me begin by saying this is a very very bad idea. For reasons, read this.
I use two techniques-
- Call Func<T> using TaskCompletionSource<TResult> as shown here
- Using Tasks to implement APM pattern as shown here
Let’s say you have method with the following signature
int MyLegacyMethod(ref myType param1, string param2, int param3, out param4);
Creating an APM wrapper for a method manually is a x step process-
- A one time step – Add an extension method ToApm as shown in the second technique above to implement APM pattern using Tasks.
- Write a method MyLegacyMethodAsync as below
public Task<Tuple<int/*return type*/, myType /*ref param*/, char[] /*out param*/>> MyLegacyMethodAsync(myType param1, string param2, int param3)
{
myType param11 = param1; /* ref param for closure */
char[] param4; /* out param for closure */
var tcs = new TaskCompletionSource<Tuple<int, myType, char[]>>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
int retVal = MyLegacyMethod(ref param11 /* local var instead of ref param */, param2, param3, out param4);
var result = new Tuple<int, myType, char[]>>(retVal, param11, param4);
tcs.SetResult(result);
}
catch (Exception exc)
{
tcs.SetException(exc);
}
});
return tcs.Task;
} - Write a BeginMyLegacyMethod as below
public IAsyncResult BeginMyLegacyMethod(myType param1, string param2, int param3, AsyncCallback callback, object state)
{
return MyLegacyMethodAsync(param1, param2, param3).AsApm(callback, state);
} - Write a EndMyLegacyMethod as below
public int EndMyLegacyMethod (IAsyncResult asyncResult, out myType param1, out char[] param4)
{
var result = ((Task<Tuple<int, myType, char[]>>) asyncResult).Result;
param1 = result.Item2;
param4 = result.Item3;
return result.Item1;
}
Now we are able to use our existing APM infrastructure to make APM calls to synchronous methods.
In my scenario, I am converting classes exposed over webservices to direct project reference. There are many classes with many methods and doing this manually would be error prone and mind numbing. So I used Roslyn library and wrote a simple class that
- reads in a file
- select methods marked with [WebMethod] attributes
- Generates the above 3 methods for each such method
- Writes them to a file
I have posted this on GitHub gists so that it may help someone save some time.
Happy Coding!