首页 > 解决方案 > 从业务层到 UI 的错误处理

问题描述

我正在运行一个静态 main() 并执行一个 app.Run() 来启动一个 WPF 窗口。它基本上是一个带有一堆用户控件的视图模型。从那里,用户单击一个连接按钮,该按钮在另一个静态类中启动 Task.Run()。

当我的任务遇到异常时,它们会返回到 app.Run() 而不是连接按钮。我猜他们是在向调用线程报告,而不是在任务开始的地方。我可以在任务级别处理一些错误,但其他错误需要用户查看。

所以我的问题是将这些错误发送到 UI 的好做法是什么?

我当前的异步......

   private static async void MainMountLoopAsync()
    {
        try
        {
            if (_ctsMount == null) _ctsMount = new CancellationTokenSource();
            var ct = _ctsMount.Token;
            var task =  Task.Run(() =>
            {
                while (!ct.IsCancellationRequested)
                {
                    MoveAxes();
                }
            }, ct);
            await task;
            task.Wait(ct);
            AbortSlew();
            MainLoopRunning = false;
            SkySystem.ConnectSerial = false;
            IsSkyConnected = SkySystem.ConnectSerial;
        }
        catch (OperationCanceledException)
        {
            MainLoopRunning = false;
            MonitorLog.LogToMonitor(MonitorDevice.Telescope, MonitorCategory.Server, MonitorType.Information,
                $"{MethodBase.GetCurrentMethod().Name}, {Thread.CurrentThread.ManagedThreadId}, Cancel Main Loop Task Requested");
        }
        catch (Exception ex)
        {
            MainLoopRunning = false;
            MonitorLog.LogToMonitor(MonitorDevice.Telescope, MonitorCategory.Server, MonitorType.Error,
                $"{MethodBase.GetCurrentMethod().Name}, {Thread.CurrentThread.ManagedThreadId}, Message:{ex.Message} Stack:{ex.StackTrace}");
            AlertState = true;
            throw;
        }
    }

标签: c#wpfmvvmerror-handling

解决方案


简而言之,您的异常是未观察到的(也就是说,您正在启动并忘记任务)。

一些考虑:

  1. 如果您正在使用,请Task.Run()使用Task.ContinueWith,有很多关于如何执行此操作的示例。然而,“一劳永逸”任务(术语使用松散)的好处是您可以检查调用方法是否引发了异常并进行相应处理。

  2. 更进一步,asyncawait在可能的情况下使用。它负责延续和错误处理,它释放了 UI 并且几乎在各个方面都更整洁。

例子

public void ContinueWithOperation()  
{  
   Task<string> t = Task.Run(() => LongRunningOperation("Continuewith", 500));  
   t.ContinueWith((t1) =>  
   {  
      // check t1 for errors here
      Console.WriteLine(t1.Result);  
   });  
}  


//Fake async! very smelly
public async Task AsyncOperation()  
{
   try
   {
      string t = await Task.Run(() => LongRunningOperation("AsyncOperation", 1000));  
      Console.WriteLine(t);  
   }
   catch (Exception e)
   {
       // check for errors here
   }
} 

// Ideally 
public async Task OperationAsync()  
{
   try
   {
      string t = await LongRunningOperationAsync("AsyncOperation", 1000);  
      Console.WriteLine(t);  
   }
   catch (Exception e)
   {
       // check for errors here
   }
} 

推荐阅读