作为序言,我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;
});
}
Completed
和Errored
只是分别包含TaskContinuationOptions.OnlyOnRanToCompletion
和OnlyOnFaulted
的扩展方法。
当一切按预期进行时,此代码很有效。问题是,如果任务出现故障(即Web服务中断),则错误不会使其返回给消费者。此外,即使响应Completed
指示错误(即404),任务也标记为HttpStatusCode
。我当然希望有效地处理这些情况,使用当前的实现我无法这样做(响应项只是null)。
有没有办法在这里向用户提出错误,或者我应该完全抛弃这种方法?
答案 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>();
}