You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步方法捕获异常后未返回值,导致LoadCollection无法完成的问题

问题原因与修复方案

核心问题:死锁导致方法无法完成

你的代码出现死锁的根源是在非UI线程调用了UI相关操作,具体逻辑如下:

  1. DownloadCollectionAsync方法中使用了ConfigureAwait(false),这会让await之后的代码在非UI线程执行(脱离原同步上下文)。
  2. 反序列化出错后,catch块调用MessageBox.Show(ex.Message)——这个方法必须在UI线程才能正常执行,它会尝试切换回UI线程等待处理。
  3. 此时UI线程可能正卡在LoadCollection的await HttpClientInstance.DownloadCollectionAsync(...)处,等待该Task完成,形成互相等待的死锁:非UI线程等UI线程处理弹窗,UI线程等非UI线程返回Task,最终两个线程都被阻塞,方法永远无法完成。

另外补充:Newtonsoft的Deserialize<T>方法虽然没有显式声明异常,但实际会抛出JsonReaderException、JsonSerializationException等运行时异常,你的代码捕获异常的逻辑本身没问题,但后续的弹窗操作触发了死锁。

修复方案

方案1:将UI操作移到UI线程执行

如果一定要在捕获异常时显示弹窗,需要手动切换回UI线程(以WPF为例):

public static async Task<Collections> DownloadCollectionAsync(Project activeProject)
{
    HttpRequestMessage msg = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri(HttpClientInstance.BaseUri + "projects/get-collections/")
    };
    msg.Headers.Add("projectID", $"{activeProject.Id}");

    using (var response = await httpClient.SendAsync(msg, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
    {
        if (response.IsSuccessStatusCode)
        {
            try
            {
                using (Stream s = await response.Content.ReadAsStreamAsync())
                using (StreamReader sr = new StreamReader(s))
                using (JsonReader reader = new JsonTextReader(sr))
                {
                    JsonSerializer serializer = new JsonSerializer();
                    return serializer.Deserialize<Collections>(reader);
                }
            }
            catch (Exception ex)
            {
                // 切换到UI线程显示弹窗
                Application.Current.Dispatcher.Invoke(() => MessageBox.Show(ex.Message));
            }
        }
    }
    return null;
}

方案2:将异常抛到上层UI方法处理(更推荐)

把非UI层的代码和UI操作解耦,让上层UI方法负责处理异常和弹窗:

// 修改DownloadCollectionAsync,移除UI操作,抛出异常或记录日志
public static async Task<Collections> DownloadCollectionAsync(Project activeProject)
{
    HttpRequestMessage msg = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri(HttpClientInstance.BaseUri + "projects/get-collections/")
    };
    msg.Headers.Add("projectID", $"{activeProject.Id}");

    using (var response = await httpClient.SendAsync(msg, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
    {
        if (response.IsSuccessStatusCode)
        {
            using (Stream s = await response.Content.ReadAsStreamAsync())
            using (StreamReader sr = new StreamReader(s))
            using (JsonReader reader = new JsonTextReader(sr))
            {
                JsonSerializer serializer = new JsonSerializer();
                return serializer.Deserialize<Collections>(reader);
            }
        }
    }
    return null;
}

// 修改LoadCollection,在UI线程捕获异常并处理
internal async Task LoadCollection(Project activeProject)
{
    try
    {
        Collections collections = await HttpClientInstance.DownloadCollectionAsync(activeProject);
        if (collections != null)
        {
            MyCollection = new ObservableCollection<WindowEntity>(collections.Collection.Select(x => x.Material).ToList());
        }           
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

这种方式更符合分层设计原则,避免了非UI代码依赖UI上下文,从根源上杜绝了此类死锁问题。

内容的提问来源于stack exchange,提问作者Ryan Daley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 23:50:32