从异步方法中捕获异常(在 Caliburn.Micro 上下文中,使用 MEF 加载程序集)
Catching exceptions from async methods (in a Caliburn.Micro context with MEF loaded assemblies)
我有一个设置为使用 MEF 的 Caliburn.Micro 应用程序。
在首次加载的 ViewModel 中,我从 MEF 加载的各种程序集中遍历 classes(接口)。
在其中一个 classes 中,有一个方法定义为异步任务:
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 使用异步方法class 加载
[Export(typeof(IMyMefClass))]
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
SomeAsyncMethod();
}
private async Task SomeAsyncMethod()
{
throw new Exception("This is never caught");
}
}
问题还是如上,如何定义一个全局异常处理器来捕获这个异常?
最简单的解决方案:
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
try
{
await SomeAsyncMethod();
} catch(Exception ex) {
throw ex
}
}
// ...
}
另一个解决方案,只需重写您的 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
}
}
此解决方案还具有让所有任务 运行 并行的优点。
我有一个设置为使用 MEF 的 Caliburn.Micro 应用程序。 在首次加载的 ViewModel 中,我从 MEF 加载的各种程序集中遍历 classes(接口)。 在其中一个 classes 中,有一个方法定义为异步任务:
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 使用异步方法class 加载
[Export(typeof(IMyMefClass))]
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
SomeAsyncMethod();
}
private async Task SomeAsyncMethod()
{
throw new Exception("This is never caught");
}
}
问题还是如上,如何定义一个全局异常处理器来捕获这个异常?
最简单的解决方案:
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
try
{
await SomeAsyncMethod();
} catch(Exception ex) {
throw ex
}
}
// ...
}
另一个解决方案,只需重写您的 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
}
}
此解决方案还具有让所有任务 运行 并行的优点。