【发布时间】:2017-07-27 14:45:14
【问题描述】:
首先,我要说的是,很难详细解释我的问题,但我会尽力而为。我将用我使用的可能导致异常的详细解释或更多代码进行更新。如果我的代码乱七八糟,我很抱歉。
我读过很多同名的SO问题,但我一点运气都没有。我对这里的Thread/Task/Dispatcher了解很少,如果发现我的代码有问题,请指导我。
简介
我的应用程序每 n 分钟通过计时器执行后台任务。
后台任务:从 API 获取数据,然后生成 Window 元素作为包含数据的表单,然后打印出来。
问题:该异常目前已经发生过两次,导致无法生成两个表单文档,因此无法打印。
从TaskScheduler.UnobservedTaskException 获取的详细异常是:
在等待任务或访问其异常属性时未观察到任务的异常。结果,未观察到的异常被终结器线程重新抛出。
- 堆栈跟踪:不适用
- 内部异常:
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);
}
}
...来自InvoiceForm 和ShippingLabelForm 的异步方法CreateDocument 包含await Task.Delay(delay)。
我的代码有什么错误吗?是不是Dispatcher.Invoke用错了?是不是DispatcherPriority枚举的错误使用造成的? Task.Delay操作有问题吗?
【问题讨论】:
-
如果发现 invoiceForm.CreateDocument(invoiceTmp) 抛出的异常怎么办?
-
@mm8 我已经捕获了所有未处理的异常,我提到的那个是唯一一个被捕获的。
-
在调用 await invoiceForm.CreateDocument(invoiceTmp) 周围没有 catch 子句。
-
最后。
-
有理由以这种方式使用 Dispatcher 吗?为什么不是 TPL?
标签: c# wpf task dispatcher