Reputation: 35915
I am using the TransformBlock from the TPL Dataflow library, and I have realized that when a exception is thrown during the transform, I get a generic exception in the "Receive" method, but no mention to the original one.
In this code:
Func<Int32, Task<String>> transformer = async i => { await Task.Yield(); throw new ArgumentException("whatever error"); };
TransformBlock<Int32, String> transform = new TransformBlock<int, string>(transformer);
transform.Post(1);
try
{
var x = await transform.ReceiveAsync();
}
catch (Exception ex)
{
// catch
}
The exception ex
contains:
System.InvalidOperationException was caught
HResult=-2146233079
Message=The source completed without providing data to receive.
Source=System.Threading.Tasks.Dataflow
StackTrace:
at System.Threading.Tasks.Dataflow.Internal.Common.InitializeStackTrace(Exception exception)
--- 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`1.GetResult()
at DoubleQueueTest.Program.<testwhatever>d__5.MoveNext() in c:\Users\vtortola\Documents\Visual Studio 2013\Projects\DoubleQueueTest\DoubleQueueTest\Program.cs:line 43
InnerException:
No mention to the original exception type or its message. Is there a way to force it to throw the original one? or at least, use it as inner exception?
Upvotes: 3
Views: 2987
Reputation: 35915
I am adding this response just for completion. As @Stephen Clearly stated, the transform will fault if one of the items faults. So if your transform should not stop because a single item faults, I have used this approach:
Create a small class that represents the operation result:
class TransformResult<T>
{
public T Result { get; set; }
public ExceptionDispatchInfo Error { get; set; }
}
If there is an exception, capture it and return the result:
Func<Int32, Task<TransformResult<String>>> transformer = async i =>
{
await Task.Yield();
try
{
// do whatever
throw new ArgumentException("whatever error");
}
catch (Exception ex)
{
return new TransformResult<String>() { Error = ExceptionDispatchInfo.Capture(ex) };
}
};
And when awaiting the transform result, if the result contains an error... throw it:
var transform = new TransformBlock<int, TransformResult<String>>(transformer);
transform.Post(1);
try
{
var x = await transform.ReceiveAsync();
if (x.Error != null)
x.Error.Throw();
}
catch (Exception ex)
{
// catch
}
Upvotes: 0
Reputation: 456587
You're seeing an exception from ReceiveAsync
. The InvalidOperationException
is expected behavior.
If you want to detect or respond to block faults, then await
the IDataflowBlock.Completion
property.
Upvotes: 6