WPF,C#TPL AggregateException从未触发过

时间:2015-11-10 15:28:19

标签: c# wpf task-parallel-library

我正在尝试用WPF,C#开发一个小应用程序。我在尝试使用库TPL时遇到了一个问题,尤其是异常处理。问题是从未捕获AggregateException,程序在我作为任务传递的方法中显示异常。这是我的代码。我删除了不必要的代码:

private void RefreshOldDossierFinancementCommandExecute(KeyEventArgs e)
    {

        bool processIt = false;


        if (e != null && e.Key == Key.Enter)
            processIt = true;
        if (e == null || processIt == true)
        {
            TaskInProgress = true;
            SBMessage = "Query In progress...";
            var uischeduler = TaskScheduler.FromCurrentSynchronizationContext();
            var refreshold = Task.Factory.StartNew(() => 

            RefreshOldDossierFinancement(DossierFinancementEnteredKey));

            refreshold.ContinueWith(task => { TaskInProgress = false; },
            CancellationToken.None,
            TaskContinuationOptions.NotOnFaulted, uischeduler);
            try
            {
                refreshold.Wait();
            }

            catch (AggregateException aex) //This Exception is never fired
            {

                Messenger.Default.Send(new ExceptionMessageRefresh(aex), "DossierFinancement");

            }

        }

    }


    private void RefreshOldDossierFinancement(long dfId)
    {

        TotalContrats = 0.000M;
        TotalMefs = 0.000M;
        TotalCommandes = 0.000M;
        decimal phb = 0.000M;
        decimal pctr = 0.000M;
        decimal pmef = 0.000M;
        PercentageHorsBilan = "(0%)";
        PercentageContrats = "(0%)";
        PercentageMef = "(0%)";
        DossierNumber = "";



        using (UnitOfWork cx = new UnitOfWork(_currentLog))
        {
           // try
            {
                IDossierFinancementRepository sr = new DossierFinancementRepository(cx, _currentLog);
                IDossierFinancementManagementService dfms = new DossierFinancementManagementService(_currentLog, sr);
                IDataTraceRepository dtr = new DataTraceRepository(cx, _currentLog);
                IDataTraceManagementService dtms = new DataTraceManagementService(_currentLog, dtr);

                CurrentDossierFinancement = dfms.FindById(dfId);

                //I put this code in comment to force a nullReferenceException exception
                /*if (CurrentDossierFinancement == null) //Not Found
                    Messenger.Default.Send<NotificationMessage>(new NotificationMessage("Dossier Financement n° " + dfId.ToString() + " introuvable."),"DossierFinancementError");
                else*/


{
//The debugger stops here with NullRefrenceException Exception
// I want this exception to be captured in AggregateException
                    DossierFinancementEnteredKey = CurrentDossierFinancement.DossierId;
                    DossierNumber = "N° " + DossierFinancementEnteredKey.ToString();
                    RequestNature = (CurrentDossierFinancement.InvestmentGoal == 0) ? "Création" : (CurrentDossierFinancement.InvestmentGoal == 1) ? "Renouvellement" : "Extension";
                    EtatDossier = (CurrentDossierFinancement.Status == 1) ? "En cours" : (CurrentDossierFinancement.Status == 2) ? "Approuvé" : "Rejeté";

                    if (CurrentDossierFinancement.ClientId != null)
                    {
                        CustomerCode = (long)CurrentDossierFinancement.ClientId;
                        CustomerName = CurrentDossierFinancement.Client.NomCli;
                    }
                    else
                    {
                        CustomerCode = 0;
                        if (CurrentDossierFinancement.ClientType == 1)
                            CustomerName = CurrentDossierFinancement.Name + " " + CurrentDossierFinancement.FirstName;
                        else
                            CustomerName = CurrentDossierFinancement.CompanyName;
                    }


                    if (CurrentDossierFinancement.Contrat != null)
                    {
                        TotalContrats = CurrentDossierFinancement.Contrat.Montant;
                        TotalHorsBilan = CurrentDossierFinancement.Contrat.Montant;
                        pctr = Math.Round((TotalContrats / CurrentDossierFinancement.Montant) * 100, 0);
                        PercentageContrats = "(" + pctr.ToString() + "%)";

                        if (CurrentDossierFinancement.Contrat.Mefs != null)
                        {
                            TotalMefs = CurrentDossierFinancement.Contrat.Mefs.Sum(x => x.Montant);
                            pmef = Math.Round((TotalMefs / CurrentDossierFinancement.Montant) * 100, 0);
                            PercentageMef = "(" + pmef.ToString() + "%)";
                        }
                        TotalHorsBilan = TotalContrats - TotalMefs;
                        phb = Math.Round((TotalHorsBilan / CurrentDossierFinancement.Montant) * 100, 0);
                        PercentageHorsBilan = "(" + phb.ToString() + "%)";
                    }


                    //Extraire la trace
                    List<DataTrace> traceList = dtms.GetTrace(DossierFinancementEnteredKey, "DossierFinancement").ToList();
                    DataTrace newRecord = traceList.Where(xx => string.Equals(xx.ActionLib, "New", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                    if (newRecord != null)
                    {
                        CreatedBy = newRecord.Coduser;
                        CreatedAt = newRecord.ActionDate.ToString();
                    }

                }
            }
                /*
            catch (Exception ex)
            {
                throw ex;
            }*/
        }



    }

我测试了以下代码但它仍然不起作用:

Task.Run(() =>
          {     
           RefreshOldDossierFinancement(DossierFinancementEnteredKey);
          }

catch (AggregateException aex)
 {
  Messenger.Default.Send(new ExceptionMessageRefresh(aex),    "DossierFinancement");
 }}).ContinueWith(task => { TaskInProgress = false; },
           CancellationToken.None,
           TaskContinuationOptions.NotOnFaulted, uischeduler
     );

2 个答案:

答案 0 :(得分:0)

使用延续的更简单方法是使用async-await。当我们使用Task.Run执行委托,并希望异步等待它完成时,我们可以await

private async void RefreshOldDossierFinancementCommandExecute(KeyEventArgs e)
{
    bool processIt = false;
    if (e != null && e.Key == Key.Enter)
        processIt = true;

    if (!processIt)
        return;

    TaskInProgress = true;
    SBMessage = "Query In progress...";
    try
    {
        await Task.Run(() => RefreshOldDossierFinancement(DossierFinancementEnteredKey));
     }
     catch (Exception e)
     {
          // Do stuff
     }
     finally
     {
          TaskInProgress = false;         
     }
}

这样,您不需要显式捕获SynchronizationContext,并且在操作正在进行时不会阻止UI线程。

答案 1 :(得分:0)

最后我找到了一个解决方案,我不知道它是否是最好的。 我修改了我的代码如下:

 private  void RefreshOldDossierFinancementCommandExecute(KeyEventArgs e)
    {

        bool processIt = false;


        if (e != null && e.Key == Key.Enter)
            processIt = true;
        if (e == null || processIt == true)
        {
            TaskInProgress = true;
            SBMessage = "Query in progress...";
            var uischeduler = TaskScheduler.FromCurrentSynchronizationContext();
            Task.Run(() =>
                  {
                     RefreshOldDossierFinancement(DossierFinancementEnteredKey);
                   }).ContinueWith(task => { TaskInProgress = false; },
                      CancellationToken.None,
                      TaskContinuationOptions.NotOnFaulted, uischeduler);
        }
    }

我在RefreshOldDossierFinancement方法中捕获异常。诀窍在于在窗口后面的代码中添加Dispatch.BeginInvoke。

这里是RefreshOldDossierFinancement方法的代码:

  private void RefreshOldDossierFinancement(long dfId)
    {

        TotalContrats = 0.000M;
        TotalMefs = 0.000M;
        TotalCommandes = 0.000M;
        decimal phb = 0.000M;
        decimal pctr = 0.000M;
        decimal pmef = 0.000M;
        PercentageHorsBilan = "(0%)";
        PercentageContrats = "(0%)";
        PercentageMef = "(0%)";
        DossierNumber = "";



        using (UnitOfWork cx = new UnitOfWork(_currentLog))
        {
            try
            {
                IDossierFinancementRepository sr = new DossierFinancementRepository(cx, _currentLog);
                IDossierFinancementManagementService dfms = new DossierFinancementManagementService(_currentLog, sr);
                IDataTraceRepository dtr = new DataTraceRepository(cx, _currentLog);
                IDataTraceManagementService dtms = new DataTraceManagementService(_currentLog, dtr);

                CurrentDossierFinancement = dfms.FindById(dfId);

                /*if (CurrentDossierFinancement == null) //Not Found
                    Messenger.Default.Send<NotificationMessage>(new NotificationMessage("Dossier Financement n° " + dfId.ToString() + " introuvable."),"DossierFinancementError");
                else*/
                {
                    DossierFinancementEnteredKey = CurrentDossierFinancement.DossierId;
                    DossierNumber = "N° " + DossierFinancementEnteredKey.ToString();
                    RequestNature = (CurrentDossierFinancement.InvestmentGoal == 0) ? "Création" : (CurrentDossierFinancement.InvestmentGoal == 1) ? "Renouvellement" : "Extension";
                    EtatDossier = (CurrentDossierFinancement.Status == 1) ? "En cours" : (CurrentDossierFinancement.Status == 2) ? "Approuvé" : "Rejeté";

                    if (CurrentDossierFinancement.ClientId != null)
                    {
                        CustomerCode = (long)CurrentDossierFinancement.ClientId;
                        CustomerName = CurrentDossierFinancement.Client.NomCli;
                    }
                    else
                    {
                        CustomerCode = 0;
                        if (CurrentDossierFinancement.ClientType == 1)
                            CustomerName = CurrentDossierFinancement.Name + " " + CurrentDossierFinancement.FirstName;
                        else
                            CustomerName = CurrentDossierFinancement.CompanyName;
                    }


                    if (CurrentDossierFinancement.Contrat != null)
                    {
                        TotalContrats = CurrentDossierFinancement.Contrat.Montant;
                        TotalHorsBilan = CurrentDossierFinancement.Contrat.Montant;
                        pctr = Math.Round((TotalContrats / CurrentDossierFinancement.Montant) * 100, 0);
                        PercentageContrats = "(" + pctr.ToString() + "%)";

                        if (CurrentDossierFinancement.Contrat.Mefs != null)
                        {
                            TotalMefs = CurrentDossierFinancement.Contrat.Mefs.Sum(x => x.Montant);
                            pmef = Math.Round((TotalMefs / CurrentDossierFinancement.Montant) * 100, 0);
                            PercentageMef = "(" + pmef.ToString() + "%)";
                        }
                        TotalHorsBilan = TotalContrats - TotalMefs;
                        phb = Math.Round((TotalHorsBilan / CurrentDossierFinancement.Montant) * 100, 0);
                        PercentageHorsBilan = "(" + phb.ToString() + "%)";
                    }


                    //Extraire la trace
                    List<DataTrace> traceList = dtms.GetTrace(DossierFinancementEnteredKey, "DossierFinancement").ToList();
                    DataTrace newRecord = traceList.Where(xx => string.Equals(xx.ActionLib, "New", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                    if (newRecord != null)
                    {
                        CreatedBy = newRecord.Coduser;
                        CreatedAt = newRecord.ActionDate.ToString();
                    }

                }
            }

            catch (Exception ex)
            {
//Here i send a message to Window to display The Exception Message in a  custom Dialog
                Messenger.Default.Send(new ExceptionMessageRefresh(ex), "DossierFinancement");
            }
        }



    }

最后这里代码窗口后面的代码:

 public partial class Dossier : Window
{

    public Dossier()
    {

        InitializeComponent();
        Messenger.Default.Register<ExitMessage>(this, "DossierFinancement", (action) => CloseWindow(action));
        Messenger.Default.Register<ExceptionMessageRefresh>(this, "DossierFinancement", (action) => ShowExceptionMessage(action));
        Messenger.Default.Register<NotificationMessage>(this, "DossierFinancementInfo", (action) => ProcessNotification(action));
        Messenger.Default.Register<NotificationMessage>(this, "DossierFinancementError", (action) => ProcessErrorDialogNotification(action));

        }

    private void ProcessNotification(NotificationMessage action)
    {
        MessageBox.Show(action.Notification.ToString(), "Information", MessageBoxButton.OK,MessageBoxImage.Information);
    }


    private void ProcessErrorDialogNotification(NotificationMessage action)
    {
        MessageBox.Show(action.Notification.ToString(), "Erreur", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    private void CloseWindow(ExitMessage action)
    {
        this.Close();
        Messenger.Default.Unregister<ExitMessage>(this, "DossierFinancement");

    }


    private void ShowExceptionMessage(ExceptionMessageRefresh obj)
    {

  //Without the following Call of Dispatcher, An exception "Thread must be STA... will be fired         
   Dispatcher.BeginInvoke(new Action(() =>
        {
            UICommon.ShowErrorMessage(obj.ExceptionToRefresh);
        }));


    }

}

这就是全部。

感谢。