发送响应后的ASP.NET工作线程

时间:2011-07-20 14:37:23

标签: asp.net multithreading

我正试图在这里做一些事情,我正在获得那种让人觉得它是一个线程问题的突发事件。

我们有一个ASP.NET 4应用程序,希望使用一些会话信息记录数据库中的每个页面请求。我们还想看看每个页面生成了多长时间,因此我们有一个基页,应用程序中的所有页面都来自该页面,我们覆盖它的OnUnload事件。在该处理程序中,我们从以下页面获取页面生成时间:

DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds
这是有效的。但后来我们决定尝试异步;如果客户端不必等待插入该日志记录,则可能会更快地传递页面。所以我试过这样的事情:

ThreadPool.QueueUserWorkItem(new WaitCallback(LogPageRequest));

但正如我所说,有时候它会起作用,有时却不起作用。服务器是否因为请求已完成而终止我的工作线程?有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

绝不应在ASP.NET中使用

ThreadPool.QueueUserWorkItem。问题是线程池线程可能有也可能没有页面上下文(如果它确实有页面上下文,则可能是另一个页面!)。回调也永远不会运行(例如,任何时候回收应用程序池)。

BackgroundWorker和其他基于SynchronizationContext的解决方案之所以有效,是因为它们可以恢复其回调中的页面上下文(以及身份和文化);有关SynchronizationContext如何使用ASP.NET(以及为什么),请参阅my MSDN article。但是,他们也会阻止页面请求,直到完成。

如果您希望在页面请求完成后执行操作,则应为此使用单独的服务。本地WCF或Windows服务将是一个很好的解决方案。

答案 1 :(得分:0)

我认为这不是被杀死的工作线程,而是HttpContext.Current实例。尝试将该时间戳值放入其自己的变量中,然后将其排队到线程池(换句话说,在它周围创建一个闭包)这样,当线程池准备好执行日志记录方法时,目标值仍然存在

...
// generate response
var time = DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds; 
ThreadPool.QueueUserWorkItem( o => {
  SaveTimeToDatabase(time);
});

//return response

如果你不想使用闭包,你也可以将时间值传递给ThreadPool.QueueUserWorkItem:

var time = DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds; 
ThreadPool.QueueUserWorkItem(new WaitCallback(LogPageRequest), time);  // the object passed into LogPageRequest will now be the time to save to the database
...