为移动应用Web服务调用任务添加超时机制避免任务取消
解决Web服务调用超时及任务取消问题
你的核心问题是Web服务响应过慢导致任务被系统取消,还没法正常检查响应状态码。我们可以从给Web请求添加可控超时机制和优化异常处理、性能两个维度来解决,下面一步步来调整代码:
1. 在HelperFile中添加自定义超时逻辑
原来的GetResponseString依赖HttpClient默认超时(100秒),但系统可能因为等待过久直接取消任务,导致你拿不到响应对象。改用Task.WhenAny结合延迟任务的方式,既能自定义超时时间,还能确保在请求完成或超时后都能明确处理,不会丢失响应码的检查机会。
修改后的HelperFile代码:
public class HelperFile { // 自定义超时时间,比如设置为30秒,可根据需求调整 private readonly TimeSpan _requestTimeout = TimeSpan.FromSeconds(30); public async Task<string> GetResponseString(Uri url) { using (HttpClient client = new HttpClient()) { // 同时启动Web请求和超时等待任务 var requestTask = client.GetAsync(url); var timeoutTask = Task.Delay(_requestTimeout); // 等待先完成的任务 var completedTask = await Task.WhenAny(requestTask, timeoutTask); if (completedTask == timeoutTask) { // 触发超时,抛出明确的超时异常,方便上层处理 throw new TimeoutException("Web服务请求超时,请稍后重试"); } else { // 请求正常完成,获取响应并检查状态码 using (HttpResponseMessage response = await requestTask) { if (response.IsSuccessStatusCode) { using (HttpContent content = response.Content) { return await content.ReadAsStringAsync(); } } else { // 抛出包含状态码的异常,让上层知道具体HTTP错误 throw new HttpRequestException($"请求失败,状态码:{(int)response.StatusCode}"); } } } } } }
为什么选这种方式?
- 比直接设置
client.Timeout更灵活:能在超时前做自定义处理,还能区分"主动取消任务"和"超时"两种不同场景 - 确保你一定能拿到响应对象(只要请求没超时),不会因为系统强制取消任务而丢失响应码的检查机会
2. 优化ProcessData的异常处理与性能
原来的代码还有两个小问题:每次循环都创建SQLite连接(性能浪费),以及没有针对性捕获超时/HTTP异常,导致错误信息模糊。调整后的代码:
private async Task ProcessData() { try { HelperFile myHelper = new HelperFile(); Uri jsonUrl1 = new Uri("https://www.myURL.com/page.asmx/GetMyData"); var result = await myHelper.GetResponseString(jsonUrl1); jsonCredit_Union.RootObject obj = JsonConvert.DeserializeObject<jsonCredit_Union.RootObject>(result); // 把SQLite连接移到循环外,减少连接创建销毁的开销 using (SQLiteConnection conn = new SQLiteConnection(App.DB_PATH)) { conn.CreateTable<tblCredit_Union>(); foreach (KeyValuePair<string, jsonCredit_Union.JobCode> kvp in obj.Results.JobCodes) { tblCredit_Union tcu = new tblCredit_Union() { cuName = kvp.Value.cuName, cuPhone = kvp.Value.cuPhone, address1 = kvp.Value.address1, city = kvp.Value.city, state_id = kvp.Value.state_id, zip_Code = kvp.Value.zip_Code, longitude = kvp.Value.longitude, latitude = kvp.Value.latitude }; conn.Insert(tcu); } } } catch (TimeoutException ex) { // 专门处理超时情况,比如提示用户或添加重试逻辑 Console.WriteLine($"请求超时:{ex.Message}"); // 示例:最多重试3次 // for (int i = 0; i < 3; i++) { /* 重试逻辑 */ } } catch (HttpRequestException ex) { // 处理HTTP错误,比如404、500等 Console.WriteLine($"HTTP请求错误:{ex.Message}"); } catch (Exception ex) { // 兜底处理其他异常 Console.WriteLine($"发生未知错误:{ex.Message}"); } }
3. 简化OnAppearing中的异步调用
原来的Task.Run属于多余的线程切换,直接调用异步方法即可:
protected async override void OnAppearing() { base.OnAppearing(); await ProcessData(); }
这样调整后,你就能:
- 精准控制Web请求的超时时间,避免任务被系统无故取消
- 正常检查响应码,区分成功、HTTP错误、超时三种场景
- 优化SQLite操作性能,减少不必要的连接开销
- 清晰捕获并处理各类异常,不再只看到模糊的"Task was cancelled"提示
内容的提问来源于stack exchange,提问作者AETechAdm
相关产品推荐
相关产品推荐

