C#异步与同步函数使用疑问:WinForms程序提前退出、发票发送顺序异常
问题根源
两个问题的核心原因都来自异步方法的错误使用:
SendInvoice使用了async void签名:除UI事件处理器外,所有自定义异步方法都应该返回Task/Task<T>,async void方法无法被调用方等待,调用后完全无法感知它什么时候执行完成,这就是程序提前退出的核心原因。- 循环中没有等待
SendInvoice执行完成就发起下一次调用:所有请求会几乎同时发起,响应返回顺序不受控制,自然会出现前一个请求还没处理完、后一个已经发送甚至先返回的乱序问题。
修复方案
1. 修正SendInvoice方法签名与实现
- 将返回值从
void改为Task,让调用方可以等待执行完成 - 优化
HttpClient的创建:不要每次请求都新建HttpClient,会导致套接字资源耗尽,建议声明为静态实例复用
// 类级别声明静态HttpClient复用 private static readonly HttpClient _client = new HttpClient(); public async Task SendInvoice(string body) { var queryString = HttpUtility.ParseQueryString(string.Empty); var uri = "https://xxxx.xxx/SendInvoices?" + queryString; byte[] byteData = Encoding.UTF8.GetBytes(body); using (var content = new ByteArrayContent(byteData)) { content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); HttpResponseMessage response = await _client.PostAsync(uri, content); string responsebody = await response.Content.ReadAsStringAsync(); ParseResponse(response.ToString()); ParseResponse(responsebody); } }
2. 修正按钮点击事件逻辑
- 按钮点击是UI事件,可以保留
async void签名(这是唯一允许使用async void的合法场景) - 循环中每次
awaitSendInvoice,保证前一个请求处理完成后再发起下一个 - 所有请求全部处理完成后再执行应用退出逻辑
private async void button1_Click(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; try { // 你的原有循环逻辑 for(/* 原有循环条件 */) { // 原有生成XML的逻辑 string xml = ""; // 等待当前发票发送、解析全部完成,再执行下一次循环 await SendInvoice(xml); } } catch(Exception ex) { // 按需添加异常处理,比如提示用户错误信息 MessageBox.Show($"处理失败:{ex.Message}"); } finally { Cursor.Current = Cursors.Default; } // 所有任务全部完成后再退出应用 System.Windows.Forms.Application.Exit(); }
额外说明
上述修改已经完全满足你的需求:严格按顺序处理每个XML的生成、发送、解析逻辑,所有任务完成后才会退出应用。如果后续需要提升处理效率,可以批量收集所有XML后并发请求,再按原始顺序处理响应,不过需要你确认业务是否允许并发发送。
内容的提问来源于stack exchange,提问作者PanosPlat
相关产品推荐
相关产品推荐

