从异步方法中捕获异常(在具有 MEF 加载程序集的 Caliburn.Micro 上下文中)



我有一个设置为使用 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
        }
    }
    // ...
}

最新更新