【发布时间】:2015-11-21 12:11:38
【问题描述】:
出于某种奇怪的原因,System.Runtime.Remoting.Messaging.CallContext 和 AsyncLocal 类都只能使用完整的 CLR。这使得在使用可移植类库或 Windows Phone 应用程序时进行异步作用域变得非常困难,特别是因为 Windows Phone API 正在变得仅限异步;所以我们真的没有不使用 async/await 的选项。
这实际上意味着在 WPF 或 WinForms 中,我们可以编写如下方法:
private async void button_Click(object sender, EventArgs e)
{
CallContext.LogicalSetData("x", new object());
await Something();
var context = CallContext.LogicalGetData("x");
}
在 WPF 和 WinForms 中,该框架确保每次单击同一个按钮都能获得自己的上下文,并且可以独立运行。使用ThreadLocal<T> 和[ThreadStatic] 很难达到同样的效果,因为每次点击都会在 UI 线程上执行。
我的问题是,我们将如何在不支持CallContext 和AsyncLocal<T> 的Windows Phone、Store 和其他应用程序类型中解决这个问题?
一些背景资料:
我们经常希望(业务)逻辑在某种上下文中运行。此上下文可以包含业务逻辑可以在整个操作中使用的信息。在服务器环境中这很容易想象,因为您需要在数据库事务中运行请求,需要访问当前用户、租户 ID 等。但即使在客户端应用程序中,操作也可能需要访问上下文信息,例如当前正在运行的操作或日志上下文的相关 ID。在此类操作期间(例如单击事件),我们可能需要解析其他服务(来自我们的Composition Root)。为了使操作成功运行,我们可能需要在整个客户端操作中重用相同的组件,这意味着我们的 Composition Root 需要了解它正在运行的上下文。
虽然所有这些信息都可以使用服务的公共 API 的方法调用通过整个系统传递,但这不仅会迫使我们用实现细节污染应用程序中服务的 API,还会导致严重的维护问题,因为我们必须在整个系统中传递所有这些信息,并且对我们的一个组件进行简单的内部更改将通过所有方法调用在调用堆栈中传播。当涉及到我们的组合根时,我们绝对不想通过应用程序传递我们的 DI 库的一些缓存/范围对象,因为这会将我们的业务逻辑紧密耦合到外部库。显然,我们也不想传递某种service locator。
因此,在客户端应用程序中使用 CallContext 或 AsyncLocal<T> 之类的东西来实现范围非常重要。
【问题讨论】:
标签: c# .net asynchronous windows-phone