在 .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;
});
}
Completed
和 Errored
只是分别包装 TaskContinuationOptions.OnlyOnRanToCompletion
和 OnlyOnFaulted
的扩展方法。
当一切按预期进行时,此代码运行良好。问题是,如果任务出错(即 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 捆绑到安装程序中并不难。
作为序言,我 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;
});
}
Completed
和 Errored
只是分别包装 TaskContinuationOptions.OnlyOnRanToCompletion
和 OnlyOnFaulted
的扩展方法。
当一切按预期进行时,此代码运行良好。问题是,如果任务出错(即 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 捆绑到安装程序中并不难。