首先,我要说的是,我很难详细解释我的问题,但我会尽力而为。我将更新详细解释或更多我可能导致异常的代码。如果我的代码很乱,我很抱歉。
我读过很多与问题相同的SO问题,但我根本没有运气。我对Thread / Task / Dispatcher的了解很少,所以如果你发现我的代码有问题,请指导我。
Intoduction
我的应用程序每隔 n 分钟按计时器执行后台任务。
后台任务:从API获取数据,然后生成Window元素作为包含数据的表单,然后打印它们。
问题:此异常此时已发生两次,这会阻止生成两个表单文档,因此不会打印它们。
从TaskScheduler.UnobservedTaskException
获取的详细例外是:
通过等待任务或访问其Exception属性,未观察到任务的异常。结果,终结器线程重新抛出了未观察到的异常。
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);
}
}
...来自CreateDocument
和InvoiceForm
的异步方法ShippingLabelForm
包含await Task.Delay(delay)
。
我的代码是否有任何错误?是错误使用Dispatcher.Invoke
引起的吗?是由错误使用DispatcherPriority
枚举引起的吗? Task.Delay
操作有问题吗?
答案 0 :(得分:1)
TaskScheduler.UnobservedTaskException
会出现异常。如果您await
完成了所有任务,那么此事件将永远不会触发。
请注意,此事件并不一定意味着严格意义上的错误。例如,如果您放弃任务,就会发生这种情况 - 如果您的代码包含任何Task.WhenAny
次调用,则相当常见。如果“即发即弃”任务抛出异常,也会发生这种情况。在这两种情况下,它实际上并不是错误。在WhenAny
情况下,另一个任务已经完成Task.WhenAny
,因此您不关心其他任务是否引发了异常。在“火与忘记”的情况下,“忘记”的字面意思是“我不关心例外”,所以你不应该在意它是否引发了例外。
如果您意外遗漏await
,此事件仅指示错误。找到丢失的await
的最简单方法是检查内部异常的调用堆栈,然后检查该方法的调用者等,直到找到不正确await
的方法。任务。