C# TPL数据流中BroadcastBlock的重复异常

C# TPL数据流中BroadcastBlock的重复异常,c#,exception,tpl-dataflow,C#,Exception,Tpl Dataflow,我正在尝试使用TPL数据流创建管道。到目前为止,一切正常,我的管道定义如下(尽管我的问题只是广播公司、SubmissionSuccessed、submissionFailed): 我最终得到一个包含两个异常的聚合异常。现在我能做的最好的事情就是过滤这些,即: try { Task.WaitAll(submissionSucceeded.Completion, submissionFailed.Completion); } catch (AggregateException ex) {

我正在尝试使用TPL数据流创建管道。到目前为止,一切正常,我的管道定义如下(尽管我的问题只是广播公司、SubmissionSuccessed、submissionFailed):

我最终得到一个包含两个异常的聚合异常。现在我能做的最好的事情就是过滤这些,即:

try
{
    Task.WaitAll(submissionSucceeded.Completion, submissionFailed.Completion);
}
catch (AggregateException ex)
{
    var uniqueExceptions = new AggregateException(ex.Flatten().InnerExceptions.Distinct());
    Console.WriteLine("An exception was thrown.\n{0}", uniqueExceptions.Flatten());
}

但我想知道是否有更好的方法。i、 e.如果只发生一个异常,我只希望引发一个异常。我对数据流还不熟悉,所以刚刚发现了所有的约定。

我已经编写了一个TPL数据流示例(),它采用了稍微不同的方法来完成和错误处理。下面是Program.cs第171行到第201行的相关代码:

    scraper.LinkTo(fetcher, link => link != null);
    scraper.LinkTo(DataflowBlock.NullTarget<Link>());

    scraper.HandleCompletion(fetcher);

    Status.Info.Log("Fetching APOD's archive list");

    links.ForEach(link => scraper.Post(link));

    scraper.Complete();

    try
    {
        await fetcher.Completion;

        Status.Finished.Log("Fetched: {0:N0}, Skipped: {1:N0}, Errors: {2:N0}, Seconds: {3:N2}",
            fetched, skipped, errored, (DateTime.UtcNow - startedOn).TotalMilliseconds / 1000.0);
    }
    catch (AggregateException errors)
    {
        foreach (var error in errors.InnerExceptions)
            Status.Failure.Log(error.Message);
    }
    catch (TaskCanceledException)
    {
        Status.Cancelled.Log("The process was manually cancelled!");
    }
    catch (Exception error)
    {
        Status.Failure.Log(error.Message);
    }

非常重要的是,当我将对象传递到链中的第一个块时,我调用scraper.Complete()。然后,HandleCompletion扩展方法处理延拓。而且,由于我正在等待fetcher(链中要完成的最后一个块),因此很容易在try/catch中捕获任何产生的错误。

submissionsuccessed和
submissionFailed
应该是单独的块吗?如果您将它们组合成一个检查
state.postsecquenced
内部的,则可以解决问题。是的,很可能,在这种情况下。我可能真的会这么做。但是,更一般地说,这会在流分裂时发生。例如,在下面的链接中-如果在广播中引发异常,则最终会在存储处理器中复制该异常:有一个好的。我相信您的HandleCompletion方法与PropagateCompletion在引擎盖下所做的相同。你选择这样做有什么特别的原因吗?我不认为它解决了我的问题,尽管有趣的是,它确实突出了它,因为很明显,通过调用多个目标可以复制异常。
try
{
    Task.WaitAll(submissionSucceeded.Completion, submissionFailed.Completion);
}
catch (AggregateException ex)
{
    var uniqueExceptions = new AggregateException(ex.Flatten().InnerExceptions.Distinct());
    Console.WriteLine("An exception was thrown.\n{0}", uniqueExceptions.Flatten());
}
    scraper.LinkTo(fetcher, link => link != null);
    scraper.LinkTo(DataflowBlock.NullTarget<Link>());

    scraper.HandleCompletion(fetcher);

    Status.Info.Log("Fetching APOD's archive list");

    links.ForEach(link => scraper.Post(link));

    scraper.Complete();

    try
    {
        await fetcher.Completion;

        Status.Finished.Log("Fetched: {0:N0}, Skipped: {1:N0}, Errors: {2:N0}, Seconds: {3:N2}",
            fetched, skipped, errored, (DateTime.UtcNow - startedOn).TotalMilliseconds / 1000.0);
    }
    catch (AggregateException errors)
    {
        foreach (var error in errors.InnerExceptions)
            Status.Failure.Log(error.Message);
    }
    catch (TaskCanceledException)
    {
        Status.Cancelled.Log("The process was manually cancelled!");
    }
    catch (Exception error)
    {
        Status.Failure.Log(error.Message);
    }
    public static void HandleCompletion(
        this IDataflowBlock source, params IDataflowBlock[] targets)
    {
        source.Completion.ContinueWith(
            task =>
            {
                foreach (var target in targets)
                {
                    if (task.IsFaulted)
                        target.Fault(task.Exception);
                    else
                        target.Complete();
                }
            });
    }