C# 需要一个执行上下文来组合异步和TPL代码
我正在寻找一个执行上下文,它可以很好地与C# 需要一个执行上下文来组合异步和TPL代码,c#,asynchronous,task-parallel-library,async-await,executioncontext,C#,Asynchronous,Task Parallel Library,Async Await,Executioncontext,我正在寻找一个执行上下文,它可以很好地与async/await配合使用,同时以以下方式与TPL配合使用(预期行为): (2)很好地使用Task.Run() Context.Store("slot", "value"); await DoSomeAsync(); Assert.AreEqual("value", Context.Read("slot")); Context.Store("slot", "value"); var value = await ReadContext("slot");
async/await
配合使用,同时以以下方式与TPL配合使用(预期行为):
(2)很好地使用Task.Run()
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);
Context.Store("slot", "value");
var task = Task.Run(() => ReadContext("slot"));
Assert.IsNull(task.Result);
Context.Store("slot", "value");
var value = await Task.Run(() => ReadContext("slot"));
Assert.AreEqual("value", value);
(3)巧妙地处理等待的任务
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);
Context.Store("slot", "value");
var task = Task.Run(() => ReadContext("slot"));
Assert.IsNull(task.Result);
Context.Store("slot", "value");
var value = await Task.Run(() => ReadContext("slot"));
Assert.AreEqual("value", value);
(3)不是必需的,但会很好。我现在使用CallContext
,但在(2)时失败,因为即使在手动运行的任务中,也可以访问其中存储的值,即使在使用Task.Factory.StartNew(…,longlunning)
运行的任务中也是如此,后者应强制在单独的线程上运行任务
有没有办法做到这一点?你真正的问题在于你的评论: 我需要一个地方来存储ASP.NET应用程序中的NHibernate会话。如果我在请求上下文中,HttpContext可以正常工作(并尊重async/await),但一旦我跳转到手动运行的任务中,HttpContext就不可用 首先,您应该避免在ASP.NET应用程序中使用“手动运行任务”;关于这个问题我有一个新的想法 其次,在
HttpContext.Items
中存储东西有点像黑客。在少数情况下,它可能很有用,但IMO管理NHibernate会话是应该在应用程序中正确设计的。这意味着您应该在方法调用中传递会话(或提供对会话访问的服务),或者将其注入到需要它的每个类型中
所以,我真的认为你所寻找的“背景”是一个错误的解决方案。即使这是可能的,但事实并非如此
如前所述,不能同时满足要求(2)和(3)。在任务.Run
中执行的代码具有访问权限或不具有访问权限;不可能两者都有
正如您所发现的,逻辑调用上下文可以满足要求(1)和(3)(谷歌用户注意:此仅在.NET 4.5下有效,并且仅在存储不可变数据时有效;详细信息)
除非手动删除
任务中代码开头的数据(FreeNamedDataSlot
),否则无法轻松满足(1)和(2)。请运行。我认为可能还有另一种解决方案,但它需要在每次等待时定制可等待设备,这完全是麻烦、脆弱和无法维护的。您真正的问题在于您的评论:
我需要一个地方来存储ASP.NET应用程序中的NHibernate会话。如果我在请求上下文中,HttpContext可以正常工作(并尊重async/await),但一旦我跳转到手动运行的任务中,HttpContext就不可用
首先,您应该避免在ASP.NET应用程序中使用“手动运行任务”;关于这个问题我有一个新的想法
其次,在HttpContext.Items
中存储东西有点像黑客。在少数情况下,它可能很有用,但IMO管理NHibernate会话是应该在应用程序中正确设计的。这意味着您应该在方法调用中传递会话(或提供对会话访问的服务),或者将其注入到需要它的每个类型中
所以,我真的认为你所寻找的“背景”是一个错误的解决方案。即使这是可能的,但事实并非如此
如前所述,不能同时满足要求(2)和(3)。在任务.Run
中执行的代码具有访问权限或不具有访问权限;不可能两者都有
正如您所发现的,逻辑调用上下文可以满足要求(1)和(3)(谷歌用户注意:此仅在.NET 4.5下有效,并且仅在存储不可变数据时有效;详细信息)
除非手动删除任务中代码开头的数据(FreeNamedDataSlot
),否则无法轻松满足(1)和(2)。请运行。我认为可能还有另一种解决方案,但它需要在每次等待时定制可等待项,这完全是麻烦、脆弱和无法维护的。在我看来不像是正常的。你能详细说明一下吗?我不明白(2)处的断言.IsNull(这是阻塞等待任务.Result)。您的意思是类似于Assert.IsNull(task.Result,“应该为null”)
?基本上,我需要一个位置来存储ASP.NET应用程序中的NHibernate会话<如果我在请求上下文中,code>HttpContext
可以正常工作(并尊重async/await
),但一旦我跳转到手动运行的任务中,它就不可用了。无论如何,现在我意识到我想要的可能是不可能的,因为当我手动启动任务时,环境不知道我是否要等待它。@Noseratio你是对的,编辑。我很惊讶CallContext
通过task传递给池线程。像(2)一样运行,你确定吗?不管怎么说,现在(2)和(3)的要求在我看来是相互排斥的,如果我没有遗漏任何东西的话。在我看来,这不像是正常的。你能详细说明一下吗?我不明白(2)处的断言.IsNull(这是阻塞等待任务.Result)。您的意思是类似于Assert.IsNull(task.Result,“应该为null”)
?基本上,我需要一个位置来存储ASP.NET应用程序中的NHibernate会话<如果我在请求上下文中,code>HttpContext
可以正常工作(并尊重async/await
),但一旦我跳转到手动运行的任务中,它就不可用了。无论如何,现在我意识到我想要的可能是不可能的,因为当我手动启动任务时,环境不知道我是否要等待它。@Noseratio你是对的,编辑。我很惊讶CallContext
通过task传递给池线程。像(2)一样运行,你确定吗?不管怎么说,如果我没有遗漏任何东西的话,(2)和(3)的要求在我看来是相互排斥的。Stephen,我同意从上到下传递会话是最好的解决方案。然而,我知道,你有一个很大的缺点