0

我正在寻找一个执行上下文,它可以async/await通过以下方式同时与 TPL 很好地配合使用(预期行为):

async Task<string> ReadContext(string slot)
{
    // Perform some async code
    ...
    return Context.Read(slot);
}

(1) 玩得很好async/await

Context.Store("slot", "value");
await DoSomeAsync();
Assert.AreEqual("value", Context.Read("slot"));

Context.Store("slot", "value");
var value = await ReadContext("slot");
Assert.AreEqual("value", value);

(2) 玩得很好Task.Run()

Context.Store("slot", "value");
var task = Task.Run(() => ReadContext("slot"));
Assert.IsNull(task.Result);

(3) 与期待已久的人打得很好Task

Context.Store("slot", "value");
var value = await Task.Run(() => ReadContext("slot"));
Assert.AreEqual("value", value);

(3)不是必需的,但会很好。我CallContext现在使用,但它在(2)处失败,因为即使在手动运行的任务中也可以访问存储在其中的值,即使在那些运行时使用Task.Factory.StartNew(..., LongRunning)它应该强制在单独的线程上运行任务。

有没有办法做到这一点?

4

1 回答 1

4

您真正的问题在您的评论中:

我需要一个地方来在 ASP.NET 应用程序中存储 NHibernate 会话。如果我在请求上下文中,HttpContext 可以正常工作(并且尊重 async/await),但是一旦我跳入手动运行的任务,它就无法使用。

首先,您应该完全避免在 ASP.NET 应用程序中“手动运行任务”;我有一篇关于这个主题的博客文章

其次,存储东西HttpContext.Items是一种黑客行为。它在少数情况下很有用,但 IMO 管理 NHibernate 会话应该在您的应用程序中正确设计。这意味着您应该在方法调用中传递会话(或提供对会话的访问的服务)或注入到需要它的每种类型中。

所以,我真的认为像你正在寻找的“上下文”是一个错误的解决方案。即使有可能,但事实并非如此。

正如@Noseratio 所指出的,要求(2)和(3)不能同时满足。在 中执行的代码要么Task.Run有访问权限,要么没有;不可能两者兼而有之。

正如您所发现的,逻辑调用上下文可以满足要求 (1) 和 (3)(Google 员工注意:这仅适用于 .NET 4.5 并且仅当您存储不可变数据时;详情请参阅我的博客)。

没有简单的方法可以满足 (1) 和 (2),除非您手动删除 中FreeNamedDataSlot代码开头的数据 () Task.Run。我认为可能还有另一种解决方案,但它需要在每次等待时自定义等待对象,这完全是麻烦、脆弱和不可维护的。

于 2013-10-16T12:55:30.197 回答