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

时间:2015-10-14 17:51:24

标签: c# asynchronous .net-4.0 task

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

我正在尝试使用网络服务,并使异步调用对于客户端消费而言不那么混乱。我提出了:

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服务中断),则错误不会使其返回给消费者。此外,即使响应Completed指示错误(即404),任务也标记为HttpStatusCode。我当然希望有效地处理这些情况,使用当前的实现我无法这样做(响应项只是null)。

有没有办法在这里向用户提出错误,或者我应该完全抛弃这种方法?

2 个答案:

答案 0 :(得分:2)

  

有没有办法在这里向用户提出错误,或者我应该完全抛弃这种方法?

好吧,看看你的签名:

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

当客户端调用Get<T>时,它将启动异步操作,然后返回。显然,如果稍后有异常,则无法让线程及时返回并再次从此方法返回。

相反,您需要修改回调。您可以通过添加第二个回调委托轻松完成此操作:

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捆绑到安装程序中并不算太难。

答案 1 :(得分:-1)

使用异步装饰你的方法,在你的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>();
}