sr2*_*r28 9 c# asp.net multithreading httpcontext
为了澄清我的问题,我一直在开发一个应用程序,它根据用户的输入(使用excel电子表格)执行大量数据库更新/ Web服务调用.如果有很多更新,则该过程可能需要超过20分钟才能运行.
为了阻止我的用户界面冻结/超时,我一直在研究多线程,这样我就可以以异步方式运行我的长时间运行过程,同时只需在进程运行时显示动画gif.
这一切似乎与我的测试数据一起很好地运行,但是当我在实际的长时间运行过程中替换时,我得到关于HttpContext.Current.User.Identity.Name的错误.我对这个念起来从这个第一条我把它意味着,如果你在页面指令设置的"异步"属性设置为"真"和所使用的方法RegisterAsyncTask你可以再访问HttpContext.Current.然而,对我来说,这似乎并非如此.我敢肯定,这件事情我做的,所以这里是我的代码(我主要是使用下面的文章来写这个了第二条和第三条):
ASP.NET页面
<%@ Page Title="Home Page" Async="true" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="false" CodeBehind="Index.aspx.cs" Inherits="MyApp.Index" %>
Run Code Online (Sandbox Code Playgroud)
C# - RegisterAsyncTask是在单击按钮时完成的,它启动长时间运行的进程:
protected void ProcessUpdates()
{
//Register async task to allow the processing of valid updates to occurr in the background
PageAsyncTask task = new PageAsyncTask(OnBegin, OnEnd, OnTimeOut, null);
RegisterAsyncTask(task);
}
IAsyncResult OnBegin(Object sender, EventArgs e, AsyncCallback cb, object state)
{
return Worker.BeginWork(cb, state);
}
private void OnEnd(IAsyncResult asyncResult)
{
//UpdateResults list should now have been filled and can be used to fill the datagrid
dgProcessedUpdates.DataSource = Worker.UpdateResults;
dgProcessedUpdates.CurrentPageIndex = 0;
dgProcessedUpdates.DataBind();
lblProgress.Text = "Update Results: update success / failure is shown below";
}
private void OnTimeOut(IAsyncResult asyncResult)
{
lblProgress.Text = "The process has timed out. Please check if any of the updates have been processed.";
}
Run Code Online (Sandbox Code Playgroud)
C# - 工人类
public class Worker
{
public static List<AuditResult> UpdateResults = new List<AuditResult>();
private delegate void del();
//This method is called when the thread is started
public static IAsyncResult BeginWork(AsyncCallback cb, object state)
{
del processing = DoUpdateProcessing;
return processing.BeginInvoke(cb, state);
}
private static void DoUpdateProcessing()
{
//UpdateResults = ExcelFileProcessing.PassValidUpdates();
//Testing
Thread.Sleep(5000);
int i = 0;
while(i < 10)
{
AuditResult ar = new AuditResult();
ar.Result = "Successful";
ar.JobNumber = (1000 + i).ToString();
ar.NewValue = "Test New Value " + i.ToString();
ar.ResultDate = DateTime.Now.ToString();
ar.UserName = HttpContext.Current.User.Identity.Name;
UpdateResults.Add(ar);
i++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
最初我的测试代码没有包含对ar.UserName的HttpContext.Current.User.Name的调用,但是在我重新调用ExcelFileProcessing.PassValidUpdates()之后,我决定这样做.当我到达那个部分(ar.UserName = HttpContext.Current.User.Identity.Name)时,它说'对象引用没有设置为对象的实例',这表明HttpContext没有传递给第二个线程.我怎样才能做到这一点?
UPDATE
我目前已恢复到我之前的代码(最初没有工作)并简单地将HttpContext.Current作为变量传递给我的DoWork方法,因为这个问题是这样的:
创建第二个线程
protected void ProcessValidUpdates()
{
Worker workerObject = new Worker();
HttpContext ctx = HttpContext.Current;
Thread workerThread = new Thread(new ThreadStart(() =>
{
HttpContext.Current = ctx;
workerObject.DoWork();
}));
workerThread.Start();
//Loop until worker thread activates
while (!workerThread.IsAlive) ;
//Put main thread to sleep to allow the worker thread to do some work
Thread.Sleep(1000);
//Request the worker thread stop itself
workerObject.RequestStop();
//Use the Join method to block the current thread until the object's thread terminates
workerThread.Join();
//UpdateResults list should now have been filled and can be used to fill the datagrid
dgProcessedUpdates.DataSource = Worker.UpdateResults;
dgProcessedUpdates.CurrentPageIndex = 0;
dgProcessedUpdates.DataBind();
lblProgress.Text = "Update Results: update success / failure is shown below";
}
Run Code Online (Sandbox Code Playgroud)
工人阶级
public class Worker
{
//volatile hints to the compiler that this data member will be accessed by multiple threads.
private volatile bool _shouldStop;
public static List<AuditResult> UpdateResults = new List<AuditResult>();
//This method is called when the thread is started
public void DoWork()
{
while (!_shouldStop)
{
//Testing
Thread.Sleep(5000);
int i = 0;
while (i < 10)
{
AuditResult ar = new AuditResult();
ar.Result = "Successful";
ar.JobNumber = (1000 + i).ToString();
ar.NewValue = "Test New Value " + i.ToString();
ar.ResultDate = DateTime.Now.ToString();
ar.UserName = HttpContext.Current.User.Identity.Name;
UpdateResults.Add(ar);
i++;
}
}
}
public void RequestStop()
{
_shouldStop = true;
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎有效,我现在可以访问HttpContext.Current和我期望的用户名.我认为这可能在某种程度上是你们有些人提出的建议.我很欣赏Andrew Morton建议的解决方案,但目前需要进行重大改写.目前,我的进程已经调用Web服务来执行数据库操作并返回成功或失败结果.它还必须直接调用另一个BPEL服务.因此我怀疑如果我不得不将所有这些包装到另一个Web服务中,可能会有进一步的性能命中.此外,对该过程的大多数调用都不会长时间运行(可能不到10分钟),因此这只是为了解决超过20分钟的少数请求.最后,这可能仅由1或2人使用,因此一次不可能有大量请求.
但是,考虑到我目前的解决方案,有什么我应该知道的可能会让我失望吗?IIS导致问题?任何额外的帮助将非常感谢.
我在共享服务器上有一个网站。我需要批量工作,并且在另一个线程中执行此操作。它可以运行长达 1 小时(我 ping 该站点,以便工作进程不会停止)。
我沿着绑定的道路来获取当前的上下文。经过几个小时的研究和搜索,仍然无法完成。在新线程中,httpcontent.current 不存在,它与用户访问的线程不同,因此上下文没有保留,并且您无法访问登录的用户,因为他们没有登录到该线程。