在IAsyncResult中使用Async方法 [英] Using Async methods inside IAsyncResult

查看:140
本文介绍了在IAsyncResult中使用Async方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从实现 TokenProvider 类> Microsoft.ServiceBus 命名空间.我要重写以下方法

I am implementing TokenProvider class from Microsoft.ServiceBus namespace. I am overriding the following method

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 .有解决这个问题的更好方法吗?

But as mentioned in the comment above. GetCustomTokenAsync is an async method and how do I await without disturbing the signature of TokenProvider class? I wanted to make use of async nature of GetCustomTokenAsync and hence I am reluctant to use .Result. Is there any better way of solving this?

推荐答案

您需要这并非完全简单,尤其是因为 TokenProvider End * 方法不遵循APM模式.

This is not entirely straightforward, especially because the End* methods of TokenProvider do not follow the APM pattern.

要求和建议:

  • Task 实现了 IAsyncResult ,因此您可以返回任务.
  • 该任务的 state 成员必须从该属性的 IAsyncResult.AsyncState 属性返回,因此您返回的 任务将无法生成通过 async -您必须通过 TaskCompletionSource< T> 自己创建它.
  • 操作完成后,需要调用回调.
  • 如果覆盖 Begin * ,则必须还覆盖匹配的 End * .
  • Task implements IAsyncResult, so you can return a task.
  • The state member has to be returned from the IAsyncResult.AsyncState property on that task, so the task you return cannot be one generated by async - you have to create it yourself via TaskCompletionSource<T>.
  • The callback needs to be invoked when the operation completes.
  • If you override Begin*, you must also override the matching End*.

生成的代码最终变得有点复杂.您可以在我的 AsyncEx.Tasks ApmAsyncFactory.ToBegin 来避免样板a>库(当前, ApmAsyncFactory 仅位于预发行版本):

The resulting code ends up being a bit complex. You can avoid the boilerplate by using the ApmAsyncFactory.ToBegin in my AsyncEx.Tasks library (currently, ApmAsyncFactory is only in the prerelease build):

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;
}

或者,如果您想查看香肠的制作方法以及手工操作,则可以选择一种方法(请记住所有异常情况都可以到达):

Alternatively, if you wanted to see how the sausage is made and do it all by hand, one option would be (keeping in mind where all the exceptions can go):

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中使用Async方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆