Ale*_* Dn 14 asp.net asp.net-mvc asynchronous httpcontext threadpool
我有一个在ASP.NET MVC应用程序中使用的以下代码示例.此代码的目的是为排队一些长时间运行的操作创建"即发即弃"请求.
public JsonResult SomeAction() {
HttpContext ctx = HttpContext.Current;
Task.Run(() => {
HttpContext.Current = ctx;
//Other long running code here.
});
return Json("{ 'status': 'Work Queued' }");
}
Run Code Online (Sandbox Code Playgroud)
我知道这不是在异步代码中处理HttpContext.Current的好方法,但是目前我们的实现不允许我们做其他事情.我想了解这段代码有多危险......
问题:理论上可以在Task.Run中设置HttpContext,将上下文设置为另一个请求吗?
我想是的,但我不确定.我是如何理解的:Request1是从线程池中的Thread1处理的,然后当Thread1绝对处理另一个请求(Request2)时,Task.Run中的代码将设置从Request1到Request2的上下文.
也许我错了,但我对ASP.NET内部的了解不允许我正确地理解它.
谢谢!
Ond*_*dar 10
让我在你身上碰到一点内幕:
public static HttpContext Current
{
get { return ContextBase.Current as HttpContext; }
set { ContextBase.Current = value; }
}
internal class ContextBase
{
internal static object Current
{
get { return CallContext.HostContext; }
set { CallContext.HostContext = value; }
}
}
public static object HostContext
{
get
{
var executionContextReader = Thread.CurrentThread.GetExecutionContextReader();
object hostContext = executionContextReader.IllogicalCallContext.HostContext;
if (hostContext == null)
{
hostContext = executionContextReader.LogicalCallContext.HostContext;
}
return hostContext;
}
set
{
var mutableExecutionContext = Thread.CurrentThread.GetMutableExecutionContext();
if (value is ILogicalThreadAffinative)
{
mutableExecutionContext.IllogicalCallContext.HostContext = null;
mutableExecutionContext.LogicalCallContext.HostContext = value;
return;
}
mutableExecutionContext.IllogicalCallContext.HostContext = value;
mutableExecutionContext.LogicalCallContext.HostContext = null;
}
}
Run Code Online (Sandbox Code Playgroud)
所以
var context = HttpContext.Current;
Run Code Online (Sandbox Code Playgroud)
等于(伪代码)
var context = CurrentThread.HttpContext;
Run Code Online (Sandbox Code Playgroud)
在你的Task.Run
内心发生这样的事情
CurrentThread.HttpContext= context;
Run Code Online (Sandbox Code Playgroud)
Task.Run
将使用线程池中的线程启动新任务.所以你要告诉你的新线程"HttpContext属性"引用了起始线程"HttpContext属性" - 到目前为止一切都很好(以及你的起始线程完成后你将要面对的所有NullReference/Dispose异常).问题是如果你的内心
//Other long running code here.
Run Code Online (Sandbox Code Playgroud)
你有这样的陈述
var foo = await Bar();
Run Code Online (Sandbox Code Playgroud)
一旦你等待,你的当前线程将返回到线程池,并在IO完成后从线程池中获取新线程 - 想知道它的"HttpContext属性"是什么,对吧?我不知道:)很可能你会以NullReferenceException结束.
您将在这里遇到的问题是,当请求完成时,HttpContext将被丢弃。由于您不等待Task.Run的结果,因此实际上是在HttpContext的处置与它在任务中的使用之间创建竞争条件。
我很确定您的任务将遇到的唯一问题是NullReferenceException或ObjectDisposedException。我看不出有任何方式可以意外窃取另一个请求的上下文。
另外,除非您要在任务中处理和记录异常,否则您的遗忘和遗忘将会抛出,并且您永远不会知道。
签出HangFire或考虑使用消息队列来处理来自单独进程的后端作业。
归档时间: |
|
查看次数: |
4929 次 |
最近记录: |