我正在使用C#,.NET Framework 4.0和Visual Studio 2012 Premium开发Windows窗体应用程序。
我有这个方法:
private void firstPhaseBtn_Click(object sender, EventArgs e)
{
var task = Task.Factory.StartNew(() =>
{
if (_viewModel == null)
_viewModel = new MainViewModel();
this.BeginInvoke((Action)delegate()
{
labelLoading.Text = "Creando orden...";
labelLoading.Visible = true;
Models.FirstPhaseModel model = new Models.FirstPhaseModel()
{
// Set data.
};
orderNumberLabel.Text = _viewModel.FirstPhase(model);
firstPhaseBtn.Enabled = true;
labelLoading.Text = string.Empty;
labelLoading.Visible = false;
});
});
try
{
task.Wait();
}
catch (Exception)
{
MessageBox.Show(this, _viewModel.ClientCustomError, "Error");
}
}
在_viewModel.FirstPhase(model);
上,我对网络服务进行HTTP获取请求。
我的问题是try catch
块不起作用。我总是得到一个未经处理的例外。
我试图在Debug,Release中运行项目,并在Release文件夹上运行可执行文件,但我总是得到一个未处理的异常。
我还尝试将try catch
块放在任务中,但结果相同。
如何在任务中处理异常?
我也试过添加这个:
.ContinueWith(t =>
{
labelLoading.Visible = false;
labelLoading.Text = string.Empty;
MessageBox.Show(this, _viewModel.ClientCustomError, "Error");
}, TaskContinuationOptions.OnlyOnFaulted);
答案 0 :(得分:1)
问题出在这里:
this.BeginInvoke((Action)delegate()
{
labelLoading.Text = "Creando orden...";
labelLoading.Visible = true;
Models.FirstPhaseModel model = new Models.FirstPhaseModel()
{
// Set data.
};
orderNumberLabel.Text = _viewModel.FirstPhase(model);
firstPhaseBtn.Enabled = true;
labelLoading.Text = string.Empty;
labelLoading.Visible = false;
});
一旦你调用BeginInvoke
,你就可以在UI线程上有效地运行任务本身,这反过来意味着TPL不再能够跟踪和跟踪异常并将它们组合到一起AggregateException。
这是一种更容易证明问题的方法:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
BeginInvoke((Action)delegate { throw new NotImplementedException(); });
});
try
{
task.Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
如果您运行此代码,它将使应用程序崩溃(除非您已订阅相关的catch所有异常处理程序,我不记得了)。
您需要做的是移出BeginInvoke
代码(在正确的调度程序上使用任务继续)或尝试/捕获BeginInvoke()
内的全部代码。
<强>更新强>
这是我重写代码的方式:
var task = Task.Factory.StartNew(() =>
{
if (_viewModel == null)
{
_viewModel = new MainViewModel();
}
}).
ContinueWith(x =>
{
labelLoading.Text = "Creando orden...";
labelLoading.Visible = true;
Models.FirstPhaseModel model = new Models.FirstPhaseModel()
{
// Set data.
};
orderNumberLabel.Text = _viewModel.FirstPhase(model);
firstPhaseBtn.Enabled = true;
labelLoading.Text = string.Empty;
labelLoading.Visible = false;
}, TaskScheduler.Current).ContinueWith(result =>
{
if (result.IsFaulted)
{
// do something with the result and "consume" it.
_log.Error(result.Exception);
}
});
答案 1 :(得分:0)
这就是我解决问题的方法:
private void firstPhaseBtn_Click(object sender, EventArgs e)
{
string orderNumber = string.Empty;
labelLoading.Text = "Creando orden...";
labelLoading.Visible = true;
Models.FirstPhaseModel model = new Models.FirstPhaseModel()
{
// Data...
};
var task = Task.Factory.StartNew(() =>
{
if (_viewModel == null)
_viewModel = new MainViewModel();
orderNumber = _viewModel.FirstPhase(model);
})
.ContinueWith(result =>
{
if (result.IsFaulted)
{
this.BeginInvoke((Action)delegate()
{
labelLoading.Visible = false;
labelLoading.Text = string.Empty;
MessageBox.Show(this, _viewModel.ClientCustomError, "Error");
});
}
else
{
this.BeginInvoke((Action)delegate()
{
orderNumberLabel.Text = orderNumber;
firstPhaseBtn.Enabled = false;
labelLoading.Visible = false;
labelLoading.Text = string.Empty;
});
ShowStaticAttributes();
}
});
}
感谢您的回答和帮助。