寻找导致“A任务异常未被发现......”的原因......

时间:2017-03-07 11:46:43

标签: c# wpf task dispatcher

首先,我要说的是,我很难详细解释我的问题,但我会尽力而为。我将更新详细解释或更多我可能导致异常的代码。如果我的代码很乱,我很抱歉。

我读过很多与问题相同的SO问题,但我根本没有运气。我对Thread / Task / Dispatcher的了解很少,所以如果你发现我的代码有问题,请指导我。

Intoduction

我的应用程序每隔 n 分钟按计时器执行后台任务。

后台任务:从API获取数据,然后生成Window元素作为包含数据的表单,然后打印它们。

问题:此异常此时已发生两次,这会阻止生成两个表单文档,因此不会打印它们。

TaskScheduler.UnobservedTaskException获取的详细例外是:

  •   

    通过等待任务或访问其Exception属性,未观察到任务的异常。结果,终结器线程重新抛出了未观察到的异常。

  • 堆栈追踪:N / A
  • 内部例外:
      

    System.Collections.ObjectModel.ReadOnlyCollection`1 [System.Exception的]


这是我的一段代码,可能对您有用,可以找到问题的根源:

public void BackgroundTask(object sender, EventArgs e)
{
    Application.Current.Dispatcher.Invoke(
        new Action(GetInvoiceData),
        DispatcherPriority.Background,
        null
    );
}

...其中GetInvoiceData是:

public async void GetInvoiceData()
{
    try
    {
        JsonData = await ApiHelperInstance.Post(ApiParam);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {
        if (!string.IsNullOrEmpty(JsonData))
        {
            var apiReturn = new ApiReturn();

            try
            {
                apiReturn = JsonConvert.DeserializeObject<ApiReturn>(JsonData);
            }
            catch (JsonException ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (apiReturn.Result != null)
                {
                    foreach (ApiResult apiResult in apiReturn.Result)
                    {
                        InvoiceQueue.Enqueue(new Invoice(apiResult));
                    }

                    var worker = new BackgroundWorker();
                    worker.DoWork += GenerateDocumentAndPrint;
                    worker.RunWorkerAsync();
                }
            }
        }
    }
}

...而GenerateDocumentAndPrint是:

public void GenerateDocumentAndPrint(object sender, DoWorkEventArgs e)
{
    while (InvoiceQueue.Count != 0)
    {
        Dispatcher.Invoke(() =>
        {
            Invoice invoice = InvoiceQueue.Dequeue();

            var invoiceForm = new InvoiceForm();
            var shippingLabelForm = new ShippingLabelForm();

            invoiceForm.Dispatcher.Invoke(async () =>
            {
                var invoiceTmp = invoice;
                var invoiceDoc = new FixedDocument();

                try
                {
                    invoiceDoc = await invoiceForm.CreateDocument(invoiceTmp);
                }
                finally
                {
                    InvoiceDocumentName = PrintJobNameSub + " - Invoice #" + invoice.TransOrder.TransNumber;
                    PrintHelperInstance.SetPrinterByName(InvoicePrinterName);
                    PrintHelperInstance.PrintDocument(invoiceDoc.DocumentPaginator, InvoiceDocumentName);
                    invoiceForm.Close();
                }
            }, DispatcherPriority.ContextIdle);

            shippingLabelForm.Dispatcher.Invoke(async () =>
            {
                var invoiceTmp = invoice;
                var shippingLabelDoc = new FixedDocument();

                try
                {
                    shippingLabelDoc = await shippingLabelForm.CreateDocument(invoiceTmp);
                }
                finally
                {
                    ShippingLabelDocumentName = PrintJobNameSub + " - Shipping Label #" + invoice.TransOrder.TransNumber;
                    PrintHelperInstance.SetPrinterByName(ShippingLabelPrinterName);
                    PrintHelperInstance.PrintDocument(shippingLabelDoc.DocumentPaginator, ShippingLabelDocumentName);
                    shippingLabelForm.Close();
                }
            }, DispatcherPriority.ContextIdle);
        }, DispatcherPriority.Normal);
    }
}

...来自CreateDocumentInvoiceForm的异步方法ShippingLabelForm包含await Task.Delay(delay)


我的代码是否有任何错误?是错误使用Dispatcher.Invoke引起的吗?是由错误使用DispatcherPriority枚举引起的吗? Task.Delay操作有问题吗?

1 个答案:

答案 0 :(得分:1)

当未遵守任务的异常时,

TaskScheduler.UnobservedTaskException会出现异常。如果您await完成了所有任务,那么此事件将永远不会触发。

请注意,此事件并不一定意味着严格意义上的错误。例如,如果您放弃任务,就会发生这种情况 - 如果您的代码包含任何Task.WhenAny次调用,则相当常见。如果“即发即弃”任务抛出异常,也会发生这种情况。在这两种情况下,它实际上并不是错误。在WhenAny情况下,另一个任务已经完成Task.WhenAny,因此您不关心其他任务是否引发了异常。在“火与忘记”的情况下,“忘记”的字​​面意思是“我不关心例外”,所以你不应该在意它是否引发了例外。

如果您意外遗漏await,此事件仅指示错误。找到丢失的await的最简单方法是检查内部异常的调用堆栈,然后检查该方法的调用者等,直到找到不正确await的方法。任务。