Last active
August 29, 2015 13:59
-
-
Save clemensv/10841337 to your computer and use it in GitHub Desktop.
Cross-AppDomain Marshaling friendly TPL wrappers for APM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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