JNY*_*ger 21 c# exception task-parallel-library aggregateexception
我遇到了几个我打电话的问题,但里面还有flatten另一个问题!这显然意味着它们正在链中传播并被卷入另一个链中.有没有办法递归展平所有内部AggregateExceptions?通常,我将使用句柄委托处理这些,但如果有另一个内部AggregateExceeption,则返回false.我没有妥善处理这些问题吗?AggregateExceptionAggregateExceptionAggregateException
编辑:既然我已经打电话展平,看来问题是,它没有被抓住,直到后来方式在调用堆栈.这是我正在调用Flatten()的代码.要在堆栈跟踪中使用,此方法称为WriteExceptionRecord(string,FileInfo):
do
{
try
{
using (var stream = file.Open(FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(stream))
{
await writer.WriteLineAsync(data);
}
}
}
catch (AggregateException ex)
{
ex.Flatten().Handle((x) =>
{
if (x is IOException)
{
retryNeeded = true;
retryLeft--;
Thread.Sleep(500);
return true;
}
logger.ErrorException("Could not write to exception file: " + data, ex);
return false;
});
}
}
while (retryNeeded && retryLeft > 0);
Run Code Online (Sandbox Code Playgroud)
但是,堆栈跟踪显示它没有被捕获.相反,它会在调用堆栈之后被捕获.以下是出于安全原因删除了一些识别信息的跟踪:
System.AggregateException: One or more errors occurred. --->
System.AggregateException: One or more errors occurred. --->
System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share)
at PDI.LoadFileProcessing.<WriteExceptionRecord>d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.LoadFileProcessing.<ExceptionRecordProcessing>d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.ProcessPipeline.<>c__DisplayClass9.<<ProcessBatch>b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share)
at PeopleDocImporter.LoadFileProcessing.<WriteExceptionRecord>d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.LoadFileProcessing.<ExceptionRecordProcessing>d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.ProcessPipeline.<>c__DisplayClass9.<<ProcessBatch>b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share)
at PDI.LoadFileProcessing.<WriteExceptionRecord>d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.LoadFileProcessing.<ExceptionRecordProcessing>d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.ProcessPipeline.<>c__DisplayClass9.<<ProcessBatch>b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61<---
<---
System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share)
at PDI.LoadFileProcessing.<WriteExceptionRecord>d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.LoadFileProcessing.<ExceptionRecordProcessing>d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.ProcessPipeline.<>c__DisplayClass9.<<ProcessBatch>b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\J\PD\Exception.csv' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share)
at PDI.LoadFileProcessing.<WriteExceptionRecord>d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.LoadFileProcessing.<ExceptionRecordProcessing>d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.ProcessPipeline.<>c__DisplayClass9.<<ProcessBatch>b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share)
at PDI.LoadFileProcessing.<WriteExceptionRecord>d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.LoadFileProcessing.<ExceptionRecordProcessing>d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PDI.ProcessPipeline.<>c__DisplayClass9.<<ProcessBatch>b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61<---
Run Code Online (Sandbox Code Playgroud)
顺便说一句:这是由TPL-Dataflow块调用的.
Sea*_*n U 25
是的,这正是你所要求的:
AggreggateException.Flatten()
Run Code Online (Sandbox Code Playgroud)
将经历并将所有内容压缩为单个AggregateException.所以你可以使用它循环遍历所有内部异常,如下所示:
try
{
// something dangerous
}
catch (AggregateException ae)
{
foreach(var innerException in ae.Flatten().InnerExceptions)
{
// handle error
}
}
Run Code Online (Sandbox Code Playgroud)
MSDN链接:http://msdn.microsoft.com/en-us/library/system.aggregateexception.flatten.aspx
Tim*_*ird 24
请记住,'flatten'方法将为您提供一个Exceptions列表,但仍然可以在每个Exception中留下扁平的InnerExceptions.
所以我发现这还不够:
try
{
// something dangerous
}
catch (AggregateException ae)
{
foreach(Exception innerException in ae.Flatten().InnerExceptions)
{
Console.WriteLine(innerException.Message());
}
}
Run Code Online (Sandbox Code Playgroud)
因为这个例外:
System.Net.Http.HttpRequestException:发送请求时发生错误.---> System.Net.WebException:无法连接到远程服务器---> System.Net.Sockets.SocketException:A连接尝试失败,因为连接的方没有正确一段时间后响应或已建立的连接失败,因为连接主机未能在System.Net.Sockets.Socket.EndConnect(IAsyncResult的asyncResult)在System.Net.ServicePoint.ConnectSocketInternal(布尔connectFailure,插座s4中,插座S6中,插座和插座,ip地址和地址响应192.168.42.55:443 ,ConnectSocketState状态,IAsyncResult的asyncResult,异常及异常)---内部异常堆栈跟踪的末尾在System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult的asyncResult,TransportContext&上下文)在System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult的AR )---内部异常堆栈跟踪结束---
最终会像这样:
发送请求时发生错误.
修复是这样的:
foreach(Exception exInnerException in aggEx.Flatten().InnerExceptions)
{
Exception exNestedInnerException = exInnerException;
do
{
if (!string.IsNullOrEmpty(exNestedInnerException.Message))
{
Console.WriteLine(exNestedInnerException.Message);
}
exNestedInnerException = exNestedInnerException.InnerException;
}
while (exNestedInnerException != null);
}
Run Code Online (Sandbox Code Playgroud)
导致:
发送请求时发生错误.
无法连接到远程服务器
连接尝试失败,因为连接方在一段时间后没有正确响应,或者建立的连接失败,因为连接的主机无法响应192.168.42.54:443
希望能帮助别人.
这是一个老问题,但OP遇到的问题是await不会从等待的任务中公开AggregateException,而只是 AggregateException中的第一个异常.因此绕过了catch(AggregateException ex)块,并且异常被捕获到堆栈的更高位置.所以代码应该是'简单':
retryNeeded = false;
do
{
try
{
if (retryNeeded)
await Task.Delay(500); // substituted for Thread.Sleep
using (var stream = file.Open(FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(stream))
{
await writer.WriteLineAsync(data);
retryNeeded = false;
}
}
}
catch (IOException)
{
retryNeeded = true;
retryLeft--;
}
catch (Exception ex)
{
logger.ErrorException("Could not write to exception file: " + data, ex);
throw;
}
} while (retryNeeded && retryLeft > 0);
return (retryLeft > 0);
Run Code Online (Sandbox Code Playgroud)
或者,Jon Skeet的WithAllExceptions扩展方法允许通过将任务包装在另一个任务中来"保护"AggregateException以防止await的行为,因此您获得包含AggregateException的AggregateException并且await'返回'原始/内部AggregateException.
注意: AggregateException.Flatten确实以递归方式"展平",如MSDN页面上的示例所示.
编辑:改进重试延迟需要避免设置错误的异步示例.