3

我已经在我的班级中实现了 IHttpAsyncHandler 以在后台执行 5-6 个长时间运行的进程,并在每个任务开始时向客户端确认。

早些时候我使用一个会话变量并使用当前任务状态更新它,并以 5 秒的间隔从 jquery 向服务器发出异步调用请求以获取当前状态,但这种实现并不好,因为它不断地向服务器发出请求以获取状态.

然后我在我的应用程序中实现了 IHttpAsyncHandler,现在服务器本身向客户端发送确认,但根据我的实现,我只能发送一个确认!如果我尝试发送多个,则其给出错误为“对象引用未设置为对象的实例”

请检查我的示例代码。

在我的代码中,ExecuteFirst() 方法可以正常向客户端发送确认,但 ExecuteSecond() 不会发送确认其给出错误。

我看了很多,但没有找到正确的方式向客户发送多个确认。

这是我的示例代码,如果有人有任何想法,请帮助我。

Javascript

function postRequest(url) {

        var url = 'StartLongRunningProcess.ashx?JOBCODE=18'

        var xmlhttp = getRequestObject();

        xmlhttp.open("POST", url, true);


        xmlhttp.onreadystatechange =
                    function () {

                        if (xmlhttp.readyState == 4) {
                            var response = xmlhttp.responseText;
                            divResponse.innerHTML += "<p>" + response + "</p>";                             
                        }
                    }


        xmlhttp.send();

    }



 function getRequestObject() {
        var req;

        if (window.XMLHttpRequest && !(window.ActiveXObject)) {
            try {
                req = new XMLHttpRequest();
            }
            catch (e) {
                req = false;
            }
        }
        else if (window.ActiveXObject) {
            try {
                req = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
                try {
                    req = new ActiveXObject('Microsoft.XMLHTTP');
                }
                catch (e) {
                    req = false;
                }
            }
        }

        return req;
    }

StartLongRunningProcess.ashx.cs

public class StartLongRunningProcess: IHttpAsyncHandler, IRequiresSessionState
{

            private AsyncRequestResult _asyncResult;
    public void ProcessRequest(HttpContext context) {}

    public bool IsReusable
    {
        get { return true;}
    }


    public IAsyncResult BeginProcessRequest(HttpContext context, System.AsyncCallback cb, object extraData)
    {

        int32 jobCode= convert.ToInt32(context.Request["JOBCODE"]);
        _asyncResult = new AsyncRequestResult(context, cb, jobCode);

                  if(jobCode==18)
                  {

                   StartProcess18()

                  }
                  else
                  {

                   //StartProcessOther()

                  }
}



            private StartProcess18()
            {

                var task1= new Task(() =>
                {
                     ExecuteFirst();                           
                });


                var task2 = task1.ContinueWith((t1) =>
                {
                    ExecuteSecond();
                }, TaskContinuationOptions.OnlyOnRanToCompletion);

                task1.Start();
            }



    private ExecuteFirst()
    {

          //notify to client that this job has been started
         _asyncResult.CurrentContext.Response.Write("First task has been started"); 
         _asyncResult.Notify();

         // Above line of code successfully send a acknowledgement to client 

         //Doing some long running process
    }


    private ExecuteSecond()
    {

          //notify to client that this job has been started
         _asyncResult.CurrentContext.Response.Write("Second task has been started"); 

          // Above line of code giving error and if I skip it and call Notify() this also does not work.

         _asyncResult.Notify();


         //Doing some long running process
    }

    public void EndProcessRequest(IAsyncResult result)
{

}


 }

AsyncRequestResult.cs

public class AsyncRequestResult : IAsyncResult 
{
    private HttpContext context;
    private AsyncCallback callback;     

    private ManualResetEvent completeEvent = null;
    private object data;
    private object objLock = new object();
    private bool isComplete = false;        

    public AsyncRequestResult(HttpContext ctx, AsyncCallback cb, object d)
    {
        this.context = ctx;
        this.callback = cb;
        this.data = d;
    }

    public HttpContext Context
    {
        get { return this.context; }
    }

    public void Notify()
    {
        //isComplete = true;


        lock(objLock)
        {
            if(completeEvent != null)
            {
                completeEvent.Set();
            }
        }


        if (callback != null)
        {
            callback(this);
        }
    }


    public object AsyncState
    {
        get { return this.data; }
    }


    public bool CompletedSynchronously
    {
        get { return false; }
    }


    public WaitHandle AsyncWaitHandle
    {
        get
        {
            lock(objLock)
            {
                if (completeEvent == null)
                    completeEvent = new ManualResetEvent(false);

                return completeEvent;
            }
        }
    }


    public bool IsCompleted
    {
        get { return this.isComplete; }
    }

}
4

1 回答 1

1

HttpContext.Current仅当您在处理传入请求的线程中访问它时才为空。

您正在运行的延续任务很可能在没有流向延续的ThreadPool线程上运行,因此它为空。HttpContext.Current

尝试将您的 TaskScheduler 设置为TaskScheduler.FromCurrentSynchronizationContext()以便在相同的上下文中执行它。

        private StartProcess18()
        {

            var task1= new Task(() =>
            {
                 ExecuteFirst();                           
            });


            var task2 = task1.ContinueWith((t1) =>
            {
                ExecuteSecond();
            }, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext());

            task1.Start();
        }
于 2014-04-27T19:40:07.740 回答