从异步方法中捕获异常(在 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
    }
}

此解决方案还具有让所有任务 运行 并行的优点。