如何在Task.Factory.StartNew中访问HttpContext.Current?

21

我想在我的asp.net应用程序中访问HttpContext.Current

Task.Factory.Start(() =>{
    //HttpContext.Current is null here
});

我该如何解决这个错误?

3个回答

36

Task.Factory.Start会启动一个新的Thread,因为HttpContext.Context是本地线程的,所以它不会自动复制到新的Thread中,因此你需要手动传递:

var task = Task.Factory.StartNew(
    state =>
        {
            var context = (HttpContext) state;
            //use context
        },
    HttpContext.Current);

有趣的是,对我来说这个问题很奇怪。例如,在进入线程后,HttpContext的User属性变为null,尽管它在HttpContext.Current中有值。 - Giedrius
2
是的,值得注意的是,使用对HttpContext.Current的引用可能会在很多情况下起作用,但不建议这样做,而且有可能会失败。当http请求完成时,ASP运行时可能会清理对象,然后你会发现像context.Items[x]这样的东西不包含之前放置的内容。另请参见https://dev59.com/r2ox5IYBdhLWcg3w3X9S。 - Rory

8
您可以使用闭包将其在新创建的线程上可用:
var currentContext = HttpContext.Current;

Task.Factory.Start(() => {
    // currentContext is not null here
});

请记住,一个任务的生命周期可能会超过HTTP请求的生命周期,在请求完成后访问HTTPContext可能会导致有趣的结果。


我喜欢使用这种方式,而不是传递状态对象并将其转换为单独的变量... 这样很混乱。 - The Muffin Man
你所说的有趣结果,是指任务范围内的旧数据吗? - sirdank

0

正如David所指出的那样,HttpContext.Current并不总是有效。在我的情况下,大约有20分之1的时间,CurrentContext将为null。最终结果如下。

string UserName = Context.User.Identity.Name;

System.Threading.Tasks.Task.Factory.StartNew(() =>
{
    UserName ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接