【问题标题】:WPF, C# TPL AggregateException never firedWPF,C# TPL AggregateException 从未被触发
【发布时间】:2015-11-11 17:09:48
【问题描述】:

我正在尝试使用 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
     );

【问题讨论】:

  • 你为什么要在线程池上排队 Task 然后立即与 Task.Wait 同步阻塞?
  • 我是 TPL 的新手。当 Task.Run((() => ...) 不起作用时,我尝试了这个。
  • 您期望哪个内部异常?
  • NullRefrenceException。这里我在主键中输入 0,然后搜索返回 null。如您所见,我在测试返回的实体是否为空的行周围添加了注释,以强制触发异常。最终目标,我想尝试在使用 TPL 时在自定义窗口中显示异常

标签: c# wpf task-parallel-library


【解决方案1】:

使用延续的更简单方法是使用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 线程。

【讨论】:

  • @Habib 您是否在异常块内正确设置了断点?您是否开启了首次机会例外?
  • 是的,我在 SBMessage = "Query in progress..." 行的左侧设置了一个断点。当我在 await Task.Run(() => RefreshOldDossierFinancement(DossierFinancementEnteredKey)) 中按 F11 时;我立即有 NullReferenceException 并且调试器位于 DossierFinancementEnteredKey = CurrentDossierFinancement.DossierId;
  • @Habib 如果你按 F10,它会到达catch 块吗?
  • @Habib 这听起来很奇怪.. 肯定有什么不好的设置。
【解决方案2】:

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

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


    }

}

仅此而已。

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    相关资源
    最近更新 更多