2017-03-07 11 views
0

우선, 제 문제를 자세히 설명하는 것은 어렵지만 최선을 다할 것입니다. 나는 아마 예외를 야기한 나에 의해 사용 된 상세한 설명이나 더 많은 코드로 업데이트 할 것이다. 코드가 엉망이라면 유감입니다."작업의 예외가 관찰되지 않았습니다 ..."원인을 찾으십시오.

내가 읽은 동일한 제목의 많은 SO 질문이 있지만 운이별로 없습니다. Thread/Task/Dispatcher에 대한 이해가 거의 없으므로, 제 코드에 대해 잘못된 점을 발견하면 안내해주십시오.


Intoduction

내 응용 프로그램 타이머에 의해 모든 N분를 백그라운드 작업을 수행합니다.

백그라운드 작업 : API에서 데이터를 가져온 다음 데이터를 포함 할 양식으로 Window 요소를 생성 한 다음 인쇄합니다.

문제 : : 예외가 이미 두 번 발생하여 인쇄되지 않도록 두 개의 양식 문서가 생성되지 않습니다. TaskScheduler.UnobservedTaskException에서 얻을 수있다

자세한 예외입니다 :

  • 작업의 예외 (들)이 관찰되지 않았다 중 작업에 대기 또는 예외 속성에 액세스하여. 결과적으로 관찰되지 않는 예외는 finalizer 스레드에 의해 다시 발생되었습니다.

    는 스택 트레이스
  • : 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 
    ); 
} 

... :

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은 다음과 ShippingLabelFormInvoiceFormawait Task.Delay(delay) 포함 모두에서

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.


내가 작성한 코드에서 실수가 있습니까? Dispatcher.Invoke의 잘못된 사용으로 인해 발생 했습니까? 열거 형의 잘못된 사용으로 인해 발생합니까? Task.Delay 작동에 문제가 있습니까?

+0

invoiceForm.CreateDocument (invoiceTmp)에 의해 발생한 모든 예외를 catch하면 어떨까요? – mm8

+0

@ mm8 나는 모든 처리되지 않은 예외를 이미 잡았습니다. 제가 언급 한 것은 잡힌 유일한 것입니다. –

+0

invoiceForm.CreateDocument (invoiceTmp)를 기다리는 호출에는 catch 절이 없습니다. – mm8

답변

1

TaskScheduler.UnobservedTaskException은 예외가 발생하지 않는 경우 예외를받습니다.await 모든 작업을 수행하면이 이벤트가 실행되지 않습니다.

이 이벤트는 엄밀히 말해서 오류을 의미하는 것은 아닙니다. 예를 들어, 작업을 포기할 경우이 문제가 발생할 수 있습니다. 코드에 Task.WhenAny 호출이 포함되어있는 경우에는 매우 일반적입니다. 이것은 "화재 및 잊어"작업이 예외를 throw하는 경우에도 발생할 수 있습니다. 두 경우 모두 실제로 오류이 아닙니다. WhenAny의 경우 다른 작업에서 이미 Task.WhenAny을 완료 했으므로 다른 작업에서 예외가 발생했는지는 신경 쓰지 않아도됩니다. "화재와 잊기"의 경우, "잊어 버려라."는 말은 "예외는 신경 쓰지 않아"라는 뜻이므로, 예외를 던지면 신경 쓰지 않아도됩니다.

실수로 await이 누락 된 경우에만이 이벤트는 오류을 나타냅니다. 누락 된 await을 찾는 가장 쉬운 방법은 내부 예외의 호출 스택을 검사 한 다음 해당 메서드 호출자를 검사하는 등의 작업을 올바르게 수행하지 않을 때까지 수행합니다. await 작업을 수행하십시오.