在 .Net4.0 中使异步操作更漂亮

Make Async Operations prettier in .Net4.0

作为序言,我 100% 坚持使用 .Net 4.0。

我正在尝试使用 Web 服务,并使异步调用不那么混乱,以供客户端使用。我想到了:

protected void Get<T>(string uri, Action<T> callback)
{
    var client = GetNewClient();
    var request = new HttpRequestMessage(HttpMethod.Get, uri);

    client.SendAsync(request)
        .Completed(t =>
        {
            T resp = t.Result.Content.ReadAsAsync<T>().Result;
            callback(resp);
        })
        .Errored(t =>
        {
            throw t.Exception;
        });
}

CompletedErrored 只是分别包装 TaskContinuationOptions.OnlyOnRanToCompletionOnlyOnFaulted 的扩展方法。

当一切按预期进行时,此代码运行良好。问题是,如果任务出错(即 Web 服务中断),错误不会返回给消费者。此外,即使响应 HttpStatusCode 指示错误(即 404),任务也会标记为 Completed。我当然想有效地处理这些情况,对于当前的实现,我无法这样做(响应项只是空)。

这里有没有办法将错误反馈给消费者,还是我应该完全放弃这种方法?

用 async 装饰你的方法,在你的 get 方法上调用 await:

protected async Task<T> Get<T>(string uri)
{
    var client = GetNewClient();
    var response = await client.GetAsync(uri);

    // Throws an exception to the user if it was not a successful request.
    response.EnsureSuccessStatusCode();

    return await response.ReadAsAsync<T>();
}

Is there a way to raise an error back to the consumer here, or should I abandon this approach altogether?

嗯,看看你的签名:

protected void Get<T>(string uri, Action<T> callback);

当客户端调用Get<T>时,它开始异步操作然后returns。显然,如果 later 出现异常,则无法让线程及时返回并再次从该方法 return

相反,您需要修改回调。您可以通过添加第二个回调委托轻松地做到这一点:

protected void Get<T>(string uri, Action<T> callback, Action<Exception> errorCallback);

现在,当操作完成时,将调用一个 或另一个 回调。但这是在做什么,真的吗?当您已经有承诺时,只需重新引入回调。所以一个更好的解决方案是(根据 Servy 的评论更新):

protected Task<T> Get<T>(string uri)
{
  var client = GetNewClient();
  var request = new HttpRequestMessage(HttpMethod.Get, uri);

  return client.SendAsync(request)
      .ContinueWith(t => t.Result.Content.ReadAsAsync<T>())
      .Unwrap();
}

也就是说,我确实认为 最好的 方法是使用 Microsoft.Bcl.Async。将 KB2468871 捆绑到安装程序中并不难。