c# - 从业务层到 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;
}
}
解决方案
简而言之,您的异常是未观察到的(也就是说,您正在启动并忘记任务)。
一些考虑:
如果您正在使用,请
Task.Run()
使用Task.ContinueWith,有很多关于如何执行此操作的示例。然而,“一劳永逸”任务(术语使用松散)的好处是您可以检查调用方法是否引发了异常并进行相应处理。更进一步,
async
并await
在可能的情况下使用。它负责延续和错误处理,它释放了 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
}
}
推荐阅读
- android - “search?.actionView as SearchView”在移动到第二个 Activity 时崩溃
- python - 将“打字”对象作为参数传递?
- r - R 单样本 KS 测试
- azure-devops - 如何从 Azure DevOps 管道构建 docker 映像并将其推送到 GitLab 容器注册表?
- python - PySpark:使用基于其他列聚合的列模式填充 NA
- c - 在函数调用中强制转换类型是如何工作的?
- github - 如何仅合并拉取请求中的特定文件?
- arrays - ANSI C:你如何从用户那里获取输入然后反向打印?
- azure - 如何使用 Terraform Azure CAF 部署 Windows VM?
- mysql - 试图在mysql中找到第三低的薪水