【问题标题】:Unable to Step into Async Task无法进入异步任务
【发布时间】:2021-02-17 17:07:16
【问题描述】:

我已尝试通过大量类似的“如何调试异步任务”帖子和文章来实现此功能,但我仍然无法在我的 WPF 应用程序的异步方法中进入或获取触发断点。无论我如何启动或运行我的任务,或者是否选择了 CLR 异常。

至于为什么要执行任务,我真的只希望我的 WPF 应用程序的 UI 在工作完成时保持响应,以便在应用程序思考时 UI 可用于排队其他工作。

更新 1: 如果断点 ?!?! 之后的一行代码引发异常,则似乎没有命中断点。 它自身的异常只是一个 File.IO 异常(我将很快修复),其中有很多文件操作需要排序,其中一个作为请求的最小示例包括在内。 (异常不包含堆栈跟踪以确定哪个特定行被抛出,而无需手动注释掉它们,一次一个。)

具体来说,

const string APP_REG_NAMESPACE = "[Redacted]";

IProgress<int> progress;
IProgress<string> status;

public MainWindow() {
    InitializeComponent();
    this.DataContext = this;

    //Allows UI to remain responsive while work is being done.
    progress = new Progress<int>(UpdateProgress);
    status = new Progress<string>(UpdateStatus);
    
    //exceptions only appear here.
    Task.Run(() => EvalConfig(progress, status));
}

/*Removed as seemed un-needed
async Task Async_EvalConfig() {
    progress = new Progress<int>(UpdateProgress);
    status = new Progress<string>(UpdateStatus);

    //exceptions all thrown here.
    await Task.Run(() => EvalConfig(progress, status));
}*/

//This allows breakpoints to be hit on any of the 3 lines
void EvalConfig(IProgress<int> progress, IProgress<string> status) {
    //Give system a second (or 10)
    Task.Delay(5000);
    Thread.Sleep(5000);
    return;
}

//No breakpoints are ever hit, if an exception occurs anywhere, 
//even if on only the last line. 
//Exceptions are only shown at the line that actually runs the task.
void EvalConfig(IProgress<int> progress, IProgress<string> status) {
    //Give system a second
    await Task.Delay(500);
    cancellationTokenSource = new CancellationTokenSource();

    //Some long duration IO work done here to prepare data load.
    //[Redacted for brevity]

    //Check the registry for the protocol key
    if(TryGetProtocol(out string protocol)){
        //Use the protocol to connect and start doing some painfully slow work
        //[Truncated for brevity]
    }else{
        //Handle missing protocol logging and schedule for admin repair.
        //[Truncated for brevity]
    }
}

bool TryGetProtocol(out string strProtocol) {
    strProtocol = "";
    try {
        using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(APP_REG_NAMESPACE)) {
            if (key == null) {
                return false;
            } else {
                Object o = key.GetValue("");//AKA (Default)
                if (o == null) {
                    return false;
                }

                strProtocol = (o as String);
                if (string.IsNullOrEmpty(strProtocol)) {
                    return false;
                }
            }
        }
    //Oddly this didn't actually catch the error 
    //despite being super generic.
    } catch (Exception ex) {
        //Handle notification of exception.
        //[Truncated for brevity]
        return false;
    }

    return true;
}

【问题讨论】:

  • 移除你的异步方法周围的 Task.Run 包装器。做await EvalConfig(progress, status);
  • Async_EvalConfig().GetAwaiter().GetResult(); 是完全错误的。它阻止执行,因此表单永远不会显示。如果mycolelction 是一个字段或属性,它永远不会获得任何值,因为窗口的构造函数在Async_EvalConfig 完成之前不会完成。将Async_EvalConfig() 返回的Task 分配给一个字段,并且仅在您确实需要等待它完成时才等待它。
  • @Reahreic:请发布一个最小的repro,然后我们可以看到问题所在。
  • @Reahreic 您发布的代码中的错误在构造函数中,而不是循环中。如果那不是真正的代码,请发布重现实际问题的内容。你不需要做任何特别的事情来完成任务和进度。您不需要过时的 BackgroundWorker。 BGW 更难使用,无法组合任务。
  • @Reahreic await 用于避免阻塞。如果您使用 .Result.Wait().GetAwaiter().GetResult(),您将明确阻止

标签: c# wpf asynchronous task


【解决方案1】:

不是真正的答案,但我最接近让断点再次命中。

如果在任务线程的任何地方抛出异常,断点似乎不会在任务/异步代码上命中。这个奇怪的行为调试器是由一个未处理的异常引起的,即使该异常发生在?!?!断点之后。

对于未来的搜索者,在清除所有未处理的异常之前,您可能无法使用 VS 调试器进入/通过您的任务代码。 (即使程序编译愉快)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-06
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    相关资源
    最近更新 更多