我正在尝试用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
);
答案 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);
}));
}
}
这就是全部。
感谢。