C# 无法处理System.Progress回调异常
我有一个C语言的单元测试#C# 无法处理System.Progress回调异常,c#,.net,multithreading,.net-core,C#,.net,Multithreading,.net Core,我有一个C语言的单元测试# [事实] public async void DownloadAsync\u ErrorDuringProgress\u ThrowsException() { 使用var model=SetupModel(); SetDownload(); 异步任务Act() { return wait model.downloadsync(VideoUrl,DestFile,(s,e)=> { e、 Download.ProgressUpdated+=(s,e)=> { 抛出新异
[事实]
public async void DownloadAsync\u ErrorDuringProgress\u ThrowsException()
{
使用var model=SetupModel();
SetDownload();
异步任务Act()
{
return wait model.downloadsync(VideoUrl,DestFile,(s,e)=>
{
e、 Download.ProgressUpdated+=(s,e)=>
{
抛出新异常(“BOOM!”);
};
});
}
//等待行动();
等待Assert.ThrowsAsync(Act);
}
如果在事件处理程序中引发异常,则整个方法应引发异常。(另一个选项是处理/忽略异常并返回DownloadStatus.Failed,但随后我必须放置一个触发分析器的通用Catch块,并且当应该在事件中处理时,用户代码中的错误被隐藏)
对于另一个类似的事件,它按预期工作,但ProgressUpdate的行为有所不同。如果我调用“wait Act();”,则会引发异常。。。但是用ThrowsAsync捕捉异常是不可能的!回调在不同的上下文或其他地方
是System.Progress类负责触发ProgressUpdated,这意味着整个回调代码段在单独的上下文中运行,该上下文不能正确处理异常
查看System.Process的文档,我发现这可能是什么原因
提供给构造函数的任何处理程序或已注册的事件处理程序
使用ProgressChanged事件通过
SynchronizationContext实例启动时捕获该实例
构建。如果当时没有当前SynchronizationContext
在构造过程中,回调将在线程池上调用
还不清楚这个问题是在运行时发生还是仅在单元测试期间发生
有人知道发生了什么,以及如何处理这样的情况吗?我觉得这里有些东西我要学
编辑:下面是发生上下文切换的代码
private async Task DownloadFileAsync(DownloadTaskFile fileInfo)
{
Status = DownloadStatus.Downloading;
using var cancelToken = new CancellationTokenSource();
try
{
await _youTube.DownloadAsync(
(IStreamInfo)fileInfo.Stream, fileInfo.Destination, new Progress<double>(ProgressHandler), cancelToken.Token).ConfigureAwait(false);
void ProgressHandler(double percent)
{
fileInfo.Downloaded = (long)(fileInfo.Length * percent);
UpdateProgress();
if (IsCancelled)
{
try
{
cancelToken.Cancel();
}
catch (ObjectDisposedException) { } // In case task is already done.
}
}
}
catch (HttpRequestException) { Status = DownloadStatus.Failed; }
catch (TaskCanceledException) { Status = DownloadStatus.Failed; }
}
private async Task DownloadFileAsync(DownloadTaskFile fileInfo)
{
状态=下载状态。正在下载;
使用var cancelToken=new CancellationTokenSource();
尝试
{
wait_youTube.DownloadAsync(
(IStreamInfo)fileInfo.Stream、fileInfo.Destination、新进度(ProgressHandler)、cancelToken.Token.ConfigureWait(false);
无效处理程序(双百分比)
{
fileInfo.download=(长)(fileInfo.Length*百分比);
UpdateProgress();
如果(已取消)
{
尝试
{
cancelToken.Cancel();
}
捕获(ObjectDisposedException){}//以防任务已完成。
}
}
}
catch(HttpRequestException){Status=DownloadStatus.Failed;}
catch(TaskCanceledException){Status=DownloadStatus.Failed;}
}
我在哪里听说过这个未处理的错误问题?“异步无效”。此事件处理程序不是异步的,但正在异步运行。Progress
在创建时捕获当前的SynchronizationContext
,并在该上下文上运行其事件处理程序。Progress
的处理程序在逻辑上是一个事件处理程序,并被视为顶级事件处理程序
这意味着无法捕获在进度处理程序之外传播的异常。它们总是直接在上下文中运行
最好的解决方法可能是调整API,使其采用i程序
,即Progress
并不是唯一的IProgress
实现,事实上,听起来您可能想要一个直接执行进度处理程序的IProgress
实现。Progress
在创建时会捕获当前的同步上下文,并在该上下文上运行其事件处理程序。Progress
的处理程序在逻辑上是一个事件处理程序,并被视为顶级事件处理程序
这意味着无法捕获在进度处理程序之外传播的异常。它们总是直接在上下文中运行
最好的解决方法可能是调整API,使其采用i程序
,即Progress
并不是唯一的IProgress
实现,事实上,听起来您可能需要一个直接执行进度处理程序的IProgress
实现。好的,这里有一堆文本,但没有具体问题。。你想要什么?让测试顺利进行。我必须能够截获异常。你确定事件处理程序被命中了吗?你能在抛出新异常时中断并确保代码流到那里吗?并且你没有在下载函数或事件invocator中吞下任何异常吗?也许将代码发布到DownloadAsync?好的,这里有一堆文本,但没有具体问题。。你想要什么?让测试顺利进行。我必须能够截获异常。你确定事件处理程序被命中了吗?您能在抛出新异常时中断并确保代码流到那里吗?您的下载函数或事件invocator中没有任何异常?或者将代码发布到DownloadAsync?
private async Task DownloadFileAsync(DownloadTaskFile fileInfo)
{
Status = DownloadStatus.Downloading;
using var cancelToken = new CancellationTokenSource();
try
{
await _youTube.DownloadAsync(
(IStreamInfo)fileInfo.Stream, fileInfo.Destination, new Progress<double>(ProgressHandler), cancelToken.Token).ConfigureAwait(false);
void ProgressHandler(double percent)
{
fileInfo.Downloaded = (long)(fileInfo.Length * percent);
UpdateProgress();
if (IsCancelled)
{
try
{
cancelToken.Cancel();
}
catch (ObjectDisposedException) { } // In case task is already done.
}
}
}
catch (HttpRequestException) { Status = DownloadStatus.Failed; }
catch (TaskCanceledException) { Status = DownloadStatus.Failed; }
}