簡體   English   中英

在IAsyncResult中使用Async方法

[英]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包裝器

這並非完全簡單,尤其是因為TokenProviderEnd*方法遵循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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM