【问题标题】:Will caliburn.micro do the right thing with async method on ViewModel?caliburn.micro 会在 ViewModel 上使用异步方法做正确的事情吗?
【发布时间】:2021-09-03 07:26:03
【问题描述】:

如其他地方所述,新的 .NET async/await 模型像病毒一样通过软件层传播。最近的异步更改现在出现在我的视图模型中,我想知道从 public void DoStuff()public async Task DoStuff() 的安全更改声明是否安全?

谢谢!

【问题讨论】:

  • 就我个人而言,我一直在这样做,没有发现任何问题。也就是说,通过异常处理,您会得到微妙的不同结果,尤其是在您不处理 TaskScheduler.UnobservedTaskException 事件的情况下。在 .NET 4.5 中,如果您不明确地捕获这些未处理的异常,它们将被悄悄地吞下。

标签: wpf async-await caliburn.micro


【解决方案1】:

现在Caliburn.Micro对异步编程模型的支持已经很好了。

你可以做的几件事:

  • 在 Action 方法中使用 async/await。请注意,从技术上讲,操作方法是事件处理程序,您应该使用async void 而不是async Task
  • Screen 事件的异步事件处理程序,如 Activated、ViewLoaded 等。
  • Screen 方法的异步覆盖:OnInitialize、OnActivate...您可以将 then 覆盖为 protected override async void OnInitialize(){},然后在其中等待另一个任务。
  • 将协程转换为任务。使用ExecuteAsync() 扩展方法。协程在某些场景中仍然具有一些优势,例如执行上下文。
  • IHandleWithTask<TMessage> - 非常方便...

a blog post desribing some use cases 几乎没有代码 sn-ps。还有一个 GitHub repository with sample project 我曾经在 Caliburn 中玩过 async/await。

【讨论】:

  • 使用async void 而不是async Task 作为Action 方法实际上有什么好处吗?因为有一个缺点:使用async void,单元测试无法正确同步方法。未正确检测到方法中抛出的异常。
  • 我在使用 void 方法 (CM 2.0.1) 时遇到了一些问题。例如,如果您尝试在 OnInitialize() 中等待获取数据并且这发生在 UI 线程以外的线程上(在我的情况下使用 SQLite),Caliburn 将继续在 UI 线程上执行,假设初始化已完成并激活屏幕。
  • 其实是否在UI线程上并不重要。设置 OnInitialize 和 OnActivate 编写调试行,并将await Task.Delay(1000); 放入 OnInitialize。你会发现 Activate 在 Initialize 完成之前被调用...
  • @RichTea 当然这是意料之中的,因为async void 的调用者永远无法等待工作完成。它只能启动它。所有async void 方法(甚至事件处理程序)都是这种情况。使用async void 是非常危险的。
  • 使用 Caliburn.Micro 2.0.1 我在使用 async Task 方法时没有遇到任何问题。如果任务中发生异常,它会通过Coroutine.Completed 事件传播(ResultCompletionEventArgs.Error 属性包含Exception)。也可作为事件处理程序 ([Event Click] = [Action HandleClickAsync])。
【解决方案2】:

答案是“是”,从 Caliburn.Micro 1.5 开始。

release announcement

【讨论】:

    【解决方案3】:

    它是安全的,但会破坏您现有的全局异常处理。在我进行重构之后,我再也没有看到任何错误对话框,为了解决这个问题,我必须订阅 Coroutine.Completed 事件:

    Coroutine.Completed += (s, a) =>
    {
        //Do something here ...
    };
    

    您可以在 App.xaml.cs 文件中执行此操作。

    我的代码中关于如何处理我的应用程序中出现的所有可能错误的示例:

    protected override void OnStartup(StartupEventArgs e)
    {
        SetupExceptionHandlers();
        base.OnStartup(e);
    }
    
    private void SetupExceptionHandlers()
    {
        AppDomain.CurrentDomain.UnhandledException += (s, a) =>
        {
            HandleException((Exception)a.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");
        };
    
        Current.DispatcherUnhandledException += (s, a) =>
        {
            HandleException(a.Exception, "Application.Current.DispatcherUnhandledException");
            a.Handled = true;
        };
    
        TaskScheduler.UnobservedTaskException += (s, a) =>
        {
            Dispatcher.InvokeAsync(() => HandleException(a.Exception, "TaskScheduler.UnobservedTaskException"));
            a.SetObserved();
        };
    
        Coroutine.Completed += (s, a) =>
        {
            if (a.Error != null)
            {
                HandleException(a.Error, "Coroutine.Completed");
            }
        };
    }
    
    private void HandleException(Exception exception, string source)
    {
        logger.Error(exception, "Unhandled exception occured (Source: {0})", source);
    
        var msg = new ShowErrorDialogEvent(exception, exception.GetBaseException().Message);
        eventAggregator.PublishOnUIThread(msg);
    }
    

    如果您想知道,loggereventAggregator 变量是在调用 DisplayRootViewFor 之前从引导程序类中的 OnStartup 方法实例化的。

    【讨论】:

      【解决方案4】:

      Marco Amendola,Caliburn.Micro 项目的项目经理写了一篇文章,标题是:Coroutines are dead. Long live Coroutines.,因为异步/等待编程模型的出现,如果你阅读了这篇文章,他就这样命名它你会看到 async/wait 让 Coroutines 过去所做的事情变得栩栩如生,所以我假设你可以在以前使用 Coroutines 的地方安全地使用它们。我建议你阅读这篇文章。

      【讨论】:

      • 谢谢指点,我去看看。 Rob Eisenberg 今天通过 Twitter 告诉我,新版本的 caliburn.micro 将在几天内发布,支持这种模式。
      • @MichaelTeper,我很高兴听到这个消息。
      • 他们让任务和协程可以互换。它在最新的源中可用。 caliburnmicro.codeplex.com/SourceControl/changeset/c6edb740263c
      • Caliburn.Micro 1.5 已发布,支持 await / async。
      猜你喜欢
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 2014-12-17
      • 2016-03-14
      • 2014-10-05
      相关资源
      最近更新 更多