从不同的线程访问HttpContext.Current

Ray*_*ydk 53 c# asp.net session httpcontext

我有一个C#ASP.NET应用程序,它启动了大约25个不同的线程,在一个名为SiteCrawler.cs的类中运行一些方法.

HttpContext.Current.Session我要保存用户所做的搜索结果,当所有线程都完成运行它呈现给用户.我的问题是该HttpContext.Current对象在生成的线程中为null,因为它不存在.

由于应用程序是多线程的限制,我还有什么其他选项来保存用户/会话特定数据而不使用会话?

我试图搜索Stackoverflow的每一寸都找到一个解决方案,但没有任何运气....

Dmi*_*sky 75

在我的应用程序中有很多代码使用HttpContext.Current,我无法修改该代码.

worker.DoWork()从下面的示例中使用该代码.而且我必须在单独的线程中运行它.

我来到以下解决方案:

 HttpContext ctx = HttpContext.Current;
 Thread t = new Thread(new ThreadStart(() =>
                {
                    HttpContext.Current = ctx;
                    worker.DoWork();
                }));
 t.Start();
 // [... do other job ...]
 t.Join();
Run Code Online (Sandbox Code Playgroud)

  • 请注意,一般来说,这是一件坏事.例如,有时您可能会发现HttpContext.Current.Items [x]返回null而不是您放在那里的值,因为ASP在http请求完成后清理了资源.这是一种快速而肮脏的方法,可能在大多数情况下都可以工作,但不要依赖它来处理任何重要的事情. (7认同)
  • 我不同意@Rory的观点.到目前为止,当你将它与其他选项进行比较时,我认为它是最优雅的解决方案.首先,你不是克隆HttpContext而是只是传递一个引用.由于Thread可能比HttpRequest本身运行的时间更长,因此可以在访问之前轻松检查HttpContext是否为null.作为对上述代码片段的改进,传递"ctx"也可以通过WeakReference完成 - 这样线程就不会阻止HttpContext在需要时进行GC.再次根据您需要的生命周期,您可以调整上面的代码以满足您的需求.+接受的答案 (3认同)
  • 当我写下我之前的评论时,我想我没有注意到这个答案的`t.Join()`.如果后台线程在http请求之前完成,我同意_should_很好.根据我的经验,当Web请求首先完成且后台任务仍在运行时,会出现问题.注意问题不是HttpContext得到gc-ed - 显然仍然有一个引用所以它不会 - 但是ASP.NET中的某些东西删除了`HttpContext.Current`中的所有元素,所以如果你期望任何东西在那个系列中,你运气不好. (2认同)

Den*_*aub 11

看看Fritz Onion的这篇文章:在服务器端Web代码中使用线程和构建异步处理程序.这很长,但你的要求不是太微不足道.

K. Scott Allen也发表了一篇关于这个问题的文章:使用HttpContext.Current


Jes*_*ess 7

@Rory在上面做了一个评论,HttpContext即使你将它传递给Thread ,它中的某些对象也会变为null.这件事发生在我身上User.因此,您可以将用户复制到线程CurrentPrincipal,如下所示:

在控制器上下文中,保存用户:

            _user = HttpContext.Current.User;
            var processThread = new Thread(() => ThreadedCode());
            processThread.Start();
Run Code Online (Sandbox Code Playgroud)

在线程中,设置'Thread''用户:

    private static void ThreadedCode()
    {
        // Workaround for HttpContext.Current.User being null.
        // Needed for CreatedBy and RevisedBy.
        Thread.CurrentPrincipal = _user;
Run Code Online (Sandbox Code Playgroud)

请注意,HttpContext仅在请求的生命周期内可用.该线程可能比请求更长时间存在,这可能是您首先需要一个线程的原因!:)


jjs*_*erx 5

只需将 HttpContext.Current 添加到类 SiteCrawler.cs 的构造函数中

public class SiteCrawler
{
     HttpContext context = HttpContext.Current;

    public void Method()
    {
        context.WhateverYouWant
    }
}
Run Code Online (Sandbox Code Playgroud)


ysr*_*srb 3

您可以将其保存到数据库中,然后,您可以让用户的浏览器不断刷新或使用ajax或使用新的信号器来检查结果是否已写入数据库中。希望能帮助到你。