【问题标题】:Where could an UnobservedTaskException be occurring?UnobservedTaskException 可能在哪里发生?
【发布时间】:2015-05-13 06:36:15
【问题描述】:

我有一个访问 WCF 服务的 WPF 客户端。该服务运行得非常好,使用计时器每 n 分钟执行一次处理。客户端 UI 有一个ProcessNow 命令,它会覆盖服务的计时器,并立即执行处理。我试图解决一个可用性问题,即多次单击Process Now 按钮,而处理仍然很忙,导致“连接关闭”异常,来自我假设的 WCF 通信通道,然后是UnobservedTaskException

异常消息说明其原因不是没有等待任务,就是没有访问其Exception 属性。在我的解决方案中,Task 的任何地方只有两个明显的用途,一个在我的视图模型中:

async void ExecuteProcessNowCommand()
{
        await _proxy.ProcessAsync(true);
}

另一个是在同一个viewmodel中的一个小实用方法:

private void ExecuteWithTimeout(Action task, int? timeout = null)
{
    timeout = timeout ?? HostServiceConstants.ServiceControlTimeout;
    var source = new CancellationTokenSource();
    var timedTask = new Task(task, source.Token);
    timedTask.Start();
    bool done = timedTask.Wait(timeout.Value);
    if (!done)
    {
        source.Cancel();
        var frame = new StackFrame(1);
        var methodName = frame.GetMethod().Name;
        _logger.Warn("'{0}' timed out after {1} milliseconds.", methodName, timeout);
    }
}

在第一个代码摘录中,我似乎确实在等待任务,但我对第二个更怀疑,基于我在网上某处找到的示例。我用它来尝试执行非阻塞检查,例如:

bool CanExecuteProcessNowCommand()
{
    bool result = false;
    ExecuteWithTimeout(() =>
        {

            try
            {
                result = _proxy.CanUserForceProcessing();
            }
            catch (EndpointNotFoundException)
            {
                result = false;
            }
        });
    return result;
}

当我尝试更新命令按钮时,在我的 WCF 客户端中调用最后一段代码:

ProcessNow.RaiseCanExecuteChanged();

我对异步和 WCF 都很陌生,所以请原谅这里的任何明显错误。

【问题讨论】:

  • 你在哪里调用ExecuteProcessNowCommand()在你的代码?
  • 在您的第一个函数的内容周围添加一个异常处理程序并捕获一个AggregateException,然后在其中放置一个断点并查看ExceptionExceptions 属性以查看导致失败。
  • @YuvalItzchakov ExecuteProcessNowCommand() 当我单击绑定到命令的“立即处理”按钮时被 WPF 调用。我没有明确地在任何地方调用它。
  • @SteveMitcham 啊,谢谢。我把catch 块从我的摘录中去掉了,我也把它放在了我的注意力之外。我只抓到了 FaultException,这是 WCF 所期望的,当我无法让它工作时我已经放弃了。

标签: c# wpf wcf async-await


【解决方案1】:

ExecuteProcessNowCommand 不会导致这种情况。如果在 async void 方法中抛出未处理的异常,则进程被取消。所以事实并非如此。

只剩下ExecuteWithTimeout。是的,如果在timedTask 中抛出未处理的异常,它可能会导致UnObservedTaskException 的结果。

您正在等待它,等待应该观察异常,但是您正在等待超时。如果在超时后抛出异常,您将看到此行为。

您需要将延续附加到timedTask 并观察异常。

【讨论】:

  • 它实际上不是async void。我没有声明任何异步方法,但 WCF 代理生成器会声明。当我尝试抛出 FaultException 时,我在某处读到 async void 会使进程停止,所以我让 Process 返回 int。现在生成的ProcessAsync 返回Task<int>。不过要先仔细看看timedTask。你所说的似乎符合那种情况。
  • @ProfK 我相信当UnObservedTaskException 被抛出时,您可以检查InnerException 属性以找到有关原始异常发生位置的更多信息。这应该对你有帮助
猜你喜欢
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
  • 2017-12-09
  • 2014-05-02
  • 2020-08-02
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
相关资源
最近更新 更多