我有一个设置为使用 MEF 的 Caliburn.Micro 应用程序。在首次加载的 ViewModel 中,我遍历 MEF 已加载的各种程序集中的类(接口)。在其中一个类中,有一个定义为异步任务的方法:
private async Task SomeAsyncMethod()
如果此方法引发异常,则引导程序或其他任何位置的 OnUnhandledException
重写永远不会捕获它。
如何定义全局异常处理程序以捕获此异常?
AppBootstrapper.cs
按如下所述实现:https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper
此外,还添加了包含要加载到配置替代的其他程序集的文件夹,并添加了 OnUnhandledException
protected override void Configure()
{
AggregateCatalog aggregateCatalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
aggregateCatalog.Catalogs.Add(new DirectoryCatalog(ConfigurationManager.AppSettings["ExternalComponents"]));
_container = new CompositionContainer(aggregateCatalog);
CompositionBatch batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(_container);
_container.Compose(batch);
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
protected override void OnUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
// Exceptions from async methods are not caught here
MyLogger.Error(e.Exception, "Unhandled exception");
e.Handled = true;
}
主视图模型
public class MainViewModel : IShell
{
[ImportMany]
private IEnumerable<IMyMefClass> _myMefClasses;
protected override void OnViewLoaded(object view)
{
foreach (IMyMefClass instance in _myMefClasses)
{
instance.Start();
}
}
}
具有异步方法的 MEF 加载类
[Export(typeof(IMyMefClass))]
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
SomeAsyncMethod();
}
private async Task SomeAsyncMethod()
{
throw new Exception("This is never caught");
}
}
如上所述,问题仍然是如何定义全局异常处理程序来捕获此异常?
另一种解决方案,只需重写您的 OnViewLoaded 方法:
protected override void OnViewLoaded(object view)
{
var runningTasks = _myMefClasses.Select(m=>m.Start()).ToArray();
try
{
Task.WaitAll(runningTasks);
}
catch(AggregateException ex)
{
//Any exception raised by a task will be in ex.InnerExceptions
}
}
此解决方案还具有让所有任务并行运行的优点。
最简单的解决方案:
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
try
{
await SomeAsyncMethod();
} catch(Exception ex) {
throw ex
}
}
// ...
}