Skip to content

Instantly share code, notes, and snippets.

@clemensv
Last active August 29, 2015 13:59
Show Gist options
  • Save clemensv/10841337 to your computer and use it in GitHub Desktop.
Save clemensv/10841337 to your computer and use it in GitHub Desktop.
Cross-AppDomain Marshaling friendly TPL wrappers for APM
//FromAsync variant that can be used with APM across M<arshaling boundaries (you make your own TArgX overloads, please)
static class MarshalTask
{
public static Task<TResult> FromAsync<TArg1, TArg2, TResult>(Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginFunc, Func<IAsyncResult, TResult> endFunc, TArg1 arg1, TArg2 arg2)
{
var cp = new Completer<TResult>(endFunc);
var tcs = new TaskCompletionSource<TResult>(cp);
cp.TaskCompletionSource = tcs;
beginFunc(arg1, arg2,cp.Complete, null);
return tcs.Task;
}
public static Task<TResult> FromAsync<TArg1, TResult>(Func<TArg1, AsyncCallback, object, IAsyncResult> beginFunc, Func<IAsyncResult, TResult> endFunc, TArg1 arg1)
{
var cp = new Completer<TResult>(endFunc);
var tcs = new TaskCompletionSource<TResult>(cp);
cp.TaskCompletionSource = tcs;
beginFunc(arg1, cp.Complete, null);
return tcs.Task;
}
class Completer<TResult> : MarshalByRefObject
{
TaskCompletionSource<TResult> tcs;
readonly Func<IAsyncResult, TResult> endFunc;
public Completer(Func<IAsyncResult, TResult> endFunc)
{
this.endFunc = endFunc;
}
public TaskCompletionSource<TResult> TaskCompletionSource
{
get { return this.tcs; }
set { this.tcs = value; }
}
public void Complete(IAsyncResult asyncResult)
{
try
{
this.TaskCompletionSource.SetResult(endFunc(asyncResult));
}
catch (Exception e)
{
this.TaskCompletionSource.SetException(e);
}
}
}
}
// Marshalable IAsyncResult wrapper for Task (TPM doesn't cross AppDomain bounaries, APM does)
// usage like this:
// public IAsyncResult BeginGetJwtToken(string deviceId, string deviceKey, AsyncCallback callback, object state)
// {
// return new TaskAsyncResult<string>(this.GetJwtTokenAsync(deviceId, deviceKey), callback, state);
// }
//
// public string EndGetJwtToken(IAsyncResult ar)
// {
// return TaskAsyncResult<string>.GetResult(ar);
// }
public class TaskAsyncResult<T> : MarshalByRefObject, IAsyncResult
{
readonly Task<T> task;
readonly object state;
public TaskAsyncResult(Task<T> t, AsyncCallback callback, object state)
{
this.task = t;
this.state = state;
if (callback != null)
{
t.ContinueWith((completedTask) => callback(this));
}
}
public bool IsCompleted { get { return this.task.IsCompleted; } }
public WaitHandle AsyncWaitHandle { get { return ((IAsyncResult)this.task).AsyncWaitHandle; } }
public object AsyncState { get { return this.state; } }
public bool CompletedSynchronously
{
get { return ((IAsyncResult)this.task).CompletedSynchronously; }
}
public T Result
{
get
{
return this.task.Result;
}
}
public static T GetResult(IAsyncResult ar)
{
return ((TaskAsyncResult<T>)ar).Result;
}
}
public class TaskAsyncResult : MarshalByRefObject, IAsyncResult
{
readonly object state;
readonly Task task;
public TaskAsyncResult(Task t, AsyncCallback callback, object state)
{
this.task = t;
this.state = state;
if (callback != null)
{
t.ContinueWith(completedTask => callback(this));
}
}
public bool IsCompleted
{
get { return this.task.IsCompleted; }
}
public WaitHandle AsyncWaitHandle
{
get { return ((IAsyncResult) this.task).AsyncWaitHandle; }
}
public object AsyncState
{
get { return this.state; }
}
public bool CompletedSynchronously
{
get { return ((IAsyncResult) this.task).CompletedSynchronously; }
}
public static void End(IAsyncResult ar)
{
((TaskAsyncResult) ar).task.Wait();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment