![](/img/trans.png)
[英]How to throw an exception from callback in WCF Async using IAsyncResult
[英]Using Async methods inside IAsyncResult
我正在從Microsoft.ServiceBus
命名空間實現TokenProvider類。 我覆蓋以下方法
protected override IAsyncResult OnBeginGetToken(string appliesTo, string action, TimeSpan timeout, AsyncCallback callback,
object state)
{
var token = GetCustomTokenAsync(appliesTo); //How to await?
return new CompletedAsyncResult<SharedAccessSignatureToken>(token, callback, state);
}
但是正如上面評論中提到的那樣。 GetCustomTokenAsync是一個異步方法,如何在不干擾TokenProvider類簽名的情況下等待? 我想利用GetCustomTokenAsync的異步特性,因此我不願意使用.Result
。 有解決這個問題的更好方法嗎?
您需要圍繞TAP方法創建APM包裝器 。
這並非完全簡單,尤其是因為TokenProvider
的End*
方法不遵循APM模式。
要求和建議:
Task
實現IAsyncResult
,因此您可以返回任務。 state
成員必須從該任務的IAsyncResult.AsyncState
屬性返回,因此您返回的任務不能是async
生成的任務-您必須通過TaskCompletionSource<T>
自己創建它。 callback
。 Begin*
,則還必須覆蓋匹配的End*
。 結果代碼最終變得有點復雜。 您可以通過使用AsyncEx.Tasks庫中的ApmAsyncFactory.ToBegin
來避免ApmAsyncFactory.ToBegin
樣板(當前, ApmAsyncFactory
僅在ApmAsyncFactory
版本中 ):
protected override IAsyncResult OnBeginGetToken(string appliesTo, string action,
TimeSpan timeout, AsyncCallback callback, object state)
{
return ApmAsyncFactory.ToBegin(GetCustomTokenAsync(appliesTo), callback, state);
}
protected override SecurityToken OnEndGetToken(IAsyncResult result,
out DateTime cacheUntil)
{
var ret = ApmAsyncFactory.ToEnd<SharedAccessSignatureToken>(result);
cacheUntil = ...;
return ret;
}
另外,如果您想了解香腸的制作方法並手工完成,可以選擇一種方法(請記住所有例外情況都可以發生)
protected override IAsyncResult OnBeginGetToken(string appliesTo, string action,
TimeSpan timeout, AsyncCallback callback, object state)
{
var tcs = new TaskCompletionSource<SharedAccessSignatureToken>(state,
TaskCreationOptions.RunContinuationsAsynchronously);
var _ = CompleteAsync(GetCustomTokenAsync(appliesTo), callback, tcs);
// _ is ignored; it can never fault.
return tcs.Task;
}
private static async Task CompleteAsync<TResult>(Task<TResult> task,
AsyncCallback callback, TaskCompletionSource<TResult> tcs)
{
try
{
tcs.TrySetResult(await task.ConfigureAwait(false));
}
catch (OperationCanceledException ex)
{
tcs.TrySetCanceled(ex.CancellationToken);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
finally
{
// Invoke callback unsafely on the thread pool, so exceptions are global
if (callback != null)
ThreadPool.QueueUserWorkItem(state => callback((IAsyncResult)state), tcs.Task);
}
}
protected override SecurityToken OnEndGetToken(IAsyncResult result,
out DateTime cacheUntil)
{
var task = (Task<SharedAccessSignatureToken>)result;
var ret = task.GetAwaiter().GetResult();
cacheUntil = ...;
return ret;
}
我根本不會使用IAsyncResult
,而是應該返回Task<T>
並等待它。 GetCustomTokenAsync
方法也是如此。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.