游客发表

cwinform调用webapi

发帖时间:2026-10-17 04:57:52

去年帮朋友改一个库存管理的调用小工具,WinForm 界面,调用需要从他们公司的调用 WebAPI 拉实时库存数据。我原本以为加个 HttpClient 就完事,调用结果踩了一堆坑——跨线程更新 UI 崩溃、调用JSON 反序列化字段对不上、调用异步方法在按钮事件里死锁。调用这篇文章就把这些实际遇到的调用问题和解决过程记下来。

先明确场景:WinForm 是调用 .NET Framework 4.7.2,WebAPI 是调用 ASP.NET Core 写的,返回 JSON。调用按钮点击后发起请求,调用拿到数据填充 DataGridView。调用听起来简单对吧?调用但如果你直接在按钮事件里写 HttpClient.GetStringAsync().Result,界面会假死,调用严重时直接卡住不动。原因很简单:UI 线程被阻塞了,而异步操作的回调还想回到 UI 线程,互相等,死锁。

正确的做法是把按钮事件标记为 async void,然后用 await。比如:

private async void btnLoad_Click(object sender, EventArgs e) {  using (var client = new HttpClient()) {  client.BaseAddress = new Uri("https://api.example.com/"); var json = await client.GetStringAsync("inventory/list"); var items = JsonConvert.DeserializeObject<List<InventoryItem>>(json); dataGridView1.DataSource = items; } }

注意 await 之后的代码默认会回到 UI 线程(因为 WinForm 有 SynchronizationContext),所以直接给 DataGridView 赋值没问题。但如果你在 await 之前用了 .ConfigureAwait(false),那后面的代码就在线程池线程上跑,再碰控件就会抛跨线程异常。这个细节很多人忽略。

另一个坑是 HttpClient 的实例化。上面代码里每次点击都 new 一个 HttpClient,短期用没问题,但如果频繁请求,socket 会耗尽。我朋友那个工具一天点几百次,跑了一周后开始报 SocketException。后来改成静态单例,或者用 IHttpClientFactory(.NET Core 才方便,Framework 下自己写个静态类持有)。简单处理:

private static readonly HttpClient client = new HttpClient {  BaseAddress = new Uri("https://api.example.com/") };

然后所有请求共用这个实例。但要注意,如果 API 的基地址会变,就别用 BaseAddress,直接传完整 URL。

JSON 反序列化这块,我习惯用 Newtonsoft.Json。WebAPI 返回的字段名可能是 camelCase,而 C# 类属性是 PascalCase,默认对不上。要么在类属性上加 [JsonProperty("itemName")],要么在反序列化时设置 SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()。我倾向后者,省得每个属性都写特性。有一次接口返回的字段名是中文拼音缩写,比如 kcl 代表库存量,那就只能老老实实加特性映射。

错误处理不能少。WebAPI 可能返回 404、500,或者超时。GetStringAsync 遇到非成功状态码会抛 HttpRequestException,所以得包 try-catch。另外给 HttpClient 设个 Timeout,默认 100 秒太长,我一般设 10 秒。超时后抛 TaskCanceledException,要单独捕获,给用户提示“请求超时,请检查网络”。

还有个实际场景:用户连续点击按钮。第一次请求还没回来,第二次又发出去了。如果不处理,可能旧数据覆盖新数据,或者界面闪烁。我的做法是在请求期间禁用按钮,btnLoad.Enabled = false; 然后在 finally 里恢复。或者用 SemaphoreSlim 做并发控制,但 WinForm 里禁用按钮更直观。

最后提一下 POST 请求。比如要提交入库单,得用 PostAsync 加 StringContent,并设置 Content-Type 为 application/json。序列化对象时用 JsonConvert.SerializeObject。记得把 Encoding.UTF8 传进去,否则中文会乱码。我见过有人用 FormUrlEncodedContent 发 JSON,服务端解析失败,查了半天。

这些点零零散散,但每个都真实卡过我。WinForm 调 WebAPI 本身不复杂,复杂的是异步、线程、序列化这些边角。写的时候多想想 UI 线程会不会被堵,HttpClient 会不会被频繁创建,字段名能不能对上,基本就稳了。

    热门排行

    友情链接