【问题标题】:No SynchronizationContext when calling Await in a another AppDomain在另一个 AppDomain 中调用 Await 时没有 SynchronizationContext
【发布时间】:2016-04-23 02:18:42
【问题描述】:

我已经成功构建了一个插件机制,我可以在其中在单独的 AppDomain 中创建 UI 控件,并将它们作为 Form 的一部分显示在主 AppDomain 中。

这些 UI 控件会自行加载数据,因此当我打开一个表单时,会创建大约 10 个不同的插件,每个插件都需要加载其数据。

如果我同步执行,这一切都可以正常工作,但我想在每个插件中使用 async/await 模式。我的刷新方法是这样的:

protected async void RefreshData()
{ 
    _data = await LoadAsync(_taskId);  <= UI Thread     :)
    OnDataChanged();                   <= Worker Thread :( 
}

现在问题开始了。当我进入这个方法时,我在主 UI 线程上。但是当等待结束时,我在一个工作线程上,所以我在更新控件的OnDataChanged() 方法中得到一个跨线程异常。

await 应该默认使用SynchronizationContext.Current 来继续,但由于我在另一个 AppDomain 中,所以这恰好是 NULL。

所以我的问题是。如何配置 await 以在当前线程(即 UI 线程)上继续?

我知道我可以获取一个控件并执行 Invoke() 但我也在使用 MVVM 模式,这是在 View Model 中,所以我无法访问那里的任何控件,并且所有 View Model -> View 通信都是通过数据绑定完成。

【问题讨论】:

  • 我认为,多一点代码会有所帮助,因为我个人很难想象什么代码在哪里执行。此外,stackoverflow.com/questions/20521286 可能会或可能不会提供一些帮助(基本思想:使用自定义的 SynchronizationContext 进行包装,而不是依赖默认值)。
  • 我真的不知道要发布什么其他代码。 Form 位于主 appDomain 中,每个控件 + 视图模型位于单独的 AppDomain 中。这个小代码和平在视图模型中,所以它在这个单独的 AppDomain 中运行。主 UI 线程出现并启动该方法,但是当等待完成时,我在另一个线程上。 (都是因为我在一个单独的 appDomain 中 SyncronizationContext 为空)
  • 我尝试了您之前指出的文章中的建议,但也没有用:var syncCtx = SynchronizationContext.Current ?? new SynchronizationContext();_data = await LoadAsync(_taskId);syncCtx.Send(OnDataChanged, null);

标签: c# multithreading winforms async-await appdomain


【解决方案1】:

我终于想出了如何从单独的 AppDomain 中返回 UI 线程,而无需控件句柄。

由于我的视图模型总是在 UI 线程上实例化,所以我只需获取当前调度程序:

_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher

现在在我的 RefreshData 方法中,我所要做的就是在等待之后调度我想要执行的操作。

protected async void RefreshData()
{ 
    _data = await LoadAsync(_taskId);            <= UI Thread :)
    _dispatcher.Invoke(() => OnDataChanged());   <= UI Thread :)
}

这当然可以通过封装调度程序等变得更花哨。

这个想法实际上来自:MVVM Light Toolkit

【讨论】:

  • 为什么不直接捕获SynchronizationContext,然后在另一个AppDomain 中将其设置为当前?
  • 嗨,斯蒂芬,阅读了您的几篇文章后,我希望您能对此发表评论。我刚刚尝试了您的想法,但是当我尝试将 SynchronizationContext 从我的主 AppDomain 传递到插件 AppDomain 时出现以下错误:在程序集“System.Windows.Forms,版本 = 4.0”中键入“System.Windows.Forms.WindowsFormsSynchronizationContext”。 0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089' 未标记为可序列化。
  • 对不起,我对 AppDomains 知之甚少。
  • 没问题,谢谢你的建议。然而,我认为这正是主线程进入另一个 appDomain 时首先没有任何 SynchronizationContext 的原因。上下文不可序列化,因此无法在 appDomain 中重建。它也不是从 MarshalByRefObject 派生的,因此不能用作远程对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2021-01-08
  • 2021-08-15
相关资源
最近更新 更多