简体   繁体   English

WPF,C#TPL AggregateException从未触发

[英]WPF, C# TPL AggregateException never fired

I am trying to develop a small application with WPF, C#. 我正在尝试使用WPF,C#开发一个小型应用程序。 I encountered a problem when trying to use the library TPL, especially exception handling. 尝试使用库TPL时遇到问题,尤其是异常处理。 The problem is that AggregateException is never captured, and the program displays an exception in the method I passed as a task. 问题是从不捕获AggregateException,并且程序在我作为任务传递的方法中显示了异常。 here's my code. 这是我的代码。 I removed unnecessary code : 我删除了不必要的代码:

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;
            }*/
        }



    }

I tested the following code and it still doesn't work : 我测试了以下代码,但仍然无法正常工作:

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

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

A simpler approach to using continuations is to use async-await . 使用延续的一种更简单的方法是使用async-await When we execute a delegate using Task.Run , and want to asynchronously wait for it's completion, we can await it: 当我们使用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;         
     }
}

This way, you don't need to explicitly capture the SynchronizationContext , and you don't block the UI thread while the operation is on-going. 这样,您无需显式捕获SynchronizationContext ,并且在操作正在进行时也不会阻塞UI线程。

Finally i found a solution, I dont know if it is the best. 终于我找到了解决方案,我不知道这是否是最好的。 I modified my code as follows : 我将代码修改如下:

 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);
        }
    }

and i capture the exception in RefreshOldDossierFinancement Method. 我在RefreshOldDossierFinancement方法中捕获了异常。 The trick lies to add a Dispatch.BeginInvoke in code behind of the window. 诀窍在于在窗口后面的代码中添加Dispatch.BeginInvoke。

Here The code of RefreshOldDossierFinancement Method : 这里的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");
            }
        }



    }

And finally here The code Behind of The window : 最后是窗口后面的代码:

 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);
        }));


    }

}

and that's all. 就这样。

Thanks. 谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM