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

时间:2016-04-21 13:24:19

标签: c# exception async-await mef caliburn.micro

我有一个设置为使用MEF的Caliburn.Micro应用程序。 在首次加载的ViewModel中,我遍历MEF加载的各种程序集中的类(接口)。 在其中一个类中,有一个定义为异步任务的方法:

private async Task SomeAsyncMethod()

如果此方法抛出异常,则它永远不会被引导程序中的OnUnhandledException覆盖或其他任何地方捕获。

如何定义全局异常处理程序来捕获此异常?

AppBootstrapper.cs

按照此处所述实施:https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper

另外添加包含要加载到Configure覆盖的附加程序集的文件夹,并添加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");
    }
}

如上所述,问题仍然是如何定义一个全局异常处理程序来捕获此异常?

2 个答案:

答案 0 :(得分:1)

另一个解决方案是,juste重写你的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
    }
}

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

答案 1 :(得分:0)

最简单的解决方案:

public class MyMefClassImplementation : IMyMefClass
{
    public void Start()
    {
        try
        {
            await SomeAsyncMethod();
        } catch(Exception ex) {
            throw ex
        }
    }
    // ...
}