如何使用asp.net中的IHttpAsyncHandler向客户端发送多个确认

时间:2014-04-18 13:01:38

标签: c# asp.net-4.0 activexobject iasyncresult ihttpasynchandler

我已经在我的类中实现了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; }
    }

}

1 个答案:

答案 0 :(得分: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();
        }