我正试图在这里做一些事情,我正在获得那种让人觉得它是一个线程问题的突发事件。
我们有一个ASP.NET 4应用程序,希望使用一些会话信息记录数据库中的每个页面请求。我们还想看看每个页面生成了多长时间,因此我们有一个基页,应用程序中的所有页面都来自该页面,我们覆盖它的OnUnload事件。在该处理程序中,我们从以下页面获取页面生成时间:
DateTime.Now.Subtract(HttpContext.Current.Timestamp).TotalSeconds
这是有效的。但后来我们决定尝试异步;如果客户端不必等待插入该日志记录,则可能会更快地传递页面。所以我试过这样的事情:
ThreadPool.QueueUserWorkItem(new WaitCallback(LogPageRequest));
但正如我所说,有时候它会起作用,有时却不起作用。服务器是否因为请求已完成而终止我的工作线程?有更好的方法吗?
答案 0 :(得分:1)
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
...