在PCL和Windows Phone应用程序中实现异步作用域

Ste*_*ven 6 .net c# asynchronous windows-phone

出于某种奇怪的原因,只有使用完整的CLR才能使用System.Runtime.Remoting.Messaging.CallContextAsyncLocal类.这使得在使用可移植类库或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");
}
Run Code Online (Sandbox Code Playgroud)

在WPF和WinForms中,框架确保每次单击到同一个按钮都可以获得自己的上下文,并且可以单独运行.很难实现相同的使用ThreadLocal<T>,[ThreadStatic]因为每次点击都会在UI线程上执行.

我的问题是,我们如何将Windows Phone中,商店和其他应用程序类型的解决这个问题,不支持CallContextAsyncLocal<T>

一些背景资料:

我们经常希望(业务)逻辑在某种上下文中运行.此上下文可以包含业务逻辑在整个操作中可以使用的信息.在服务器环境中,这很容易想象,因为您需要在数据库事务中运行请求,需要访问当前用户,租户ID等.但即使在客户端应用程序中,操作也可能需要访问上下文信息,例如用于记录的当前运行操作或上下文的相关ID.在此类操作期间(如点击事件),我们可能需要解析其他服务(来自我们的合成根).为了使操作成功,我们可能需要在整个客户端操作中重用相同的组件,这意味着我们的组合根需要知道它正在运行的上下文.

虽然所有这些信息都可以使用服务公共API的方法调用在整个系统中传递,但这不仅会迫使我们使用实现细节污染应用程序中的服务API,还会导致严重的维护问题,因为我们必须在整个系统中传递所有这些信息,并且对我们的一个组件的简单内部更改将通过所有方法调用向上传播调用堆栈.当涉及到我们的Composition Root时,我们绝对不希望通过应用程序传递我们的DI库的一些缓存/范围对象,因为这会将我们的业务逻辑紧密地耦合到外部库.显然,我们也不想传递某种服务定位器.

因此,在客户端应用程序中使用类似CallContextAsyncLocal<T>非常重要的实现范围.

Ste*_*ary 3

抱歉,今天没有简单的解决方案。当 Windows Phone(最终)成为“手机上的 Windows 10”(即带有AsyncLocal<T>)时,这将成为可能。但现在...

最简单的方法是显式(作为参数)或隐式(作为 上的成员变量)传递上下文this

也可以通过自定义等待者来实现此功能的有限版本。但除了极其复杂之外,该解决方案还需要您修改await整个应用程序中的每个部分(或使用编译后 IL 重写来实现相同的效果)。

  • 废话。这不是我所希望的答案。 (2认同)