IHttpAsyncHandler problem


A

Alphapage

Hello,

You can find my AsyncPage class which inherits from Page and
IHttpAsyncHandler.
I inherit my default.aspx page from AsyncPage and put a linkbutton on that
page and set the PostbackUrl property to
http://localhost:port/default.aspx?test=1

I run my app, the page is displayed (no problem), I click the linkbutton
(the page sleeps during 20000ms, no problem).
The problem is if I open second tab in Internet Explorer or Firefox and go
to http://localhost:port/default.aspx when the first is still sleeping, the
second tab freezes.
It seems the Asp.Net ThreadPool thread used by the first tab is locked and
not sent back to the Asp.Net ThreadPool as it should be. So, the second tab
is pushed in the queue of this strange waiting thread and freezes until the
first tab finished sleeping.

How can I bypass this trouble ? (ie: I know all about Asynchrounous pages in
Asp.Net 2.0, but I want to implement my own threadpool)
My code seems good and is an example of:
http://msdn.microsoft.com/msdnmag/issues/03/06/Threading/default.aspx

Here is my AsyncPage class:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Threading;

namespace WebApplicationThreadPool
{
public class AsyncPage3: Page,IHttpAsyncHandler
{
static protected DevelopMentor.ThreadPool _threadPool;

static AsyncPage3()
{
_threadPool =
new DevelopMentor.ThreadPool(2, 25, "AsyncPool");
_threadPool.PropogateCallContext = true;
_threadPool.PropogateThreadPrincipal = true;
_threadPool.PropogateHttpContext = true;
_threadPool.Start();
}

public new void ProcessRequest(HttpContext ctx)
{
// not used
}

public new bool IsReusable
{
get { return false; }
}

#region IHttpAsyncHandler Members

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

context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());

AsyncRequestState reqState =
new AsyncRequestState(context, cb, extraData);


_threadPool.PostRequest(
new DevelopMentor.WorkRequestDelegate(ProcessRequest),
reqState);


context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());

return reqState;

}

public void EndProcessRequest(IAsyncResult result)
{
AsyncRequestState reqState = (AsyncRequestState)result;


reqState.ctx.Response.Output.Write("IHttpAsyncHandler.EndProcessRequest
called on thread {0}<br/>",

AppDomain.GetCurrentThreadId());
}

#endregion

void ProcessRequest(object state, DateTime requestTime)
{
AsyncRequestState reqState = state as AsyncRequestState;

if (reqState.ctx.Request.QueryString["test"]=="1")
Thread.Sleep(20000);
// Synchronously call base class Page.ProcessRequest
// as you are now on a thread pool thread.
base.ProcessRequest(reqState.ctx);


reqState.ctx.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest
called on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
//Thread.Sleep(20000);
// This triggers the asp.net plumbing to call our
// IHttpAsyncHandler.EndProcessRequest method.
//
reqState.CompleteRequest();
reqState.cb(reqState);
}

public class AsyncRequestState : IAsyncResult
{
public AsyncRequestState(HttpContext ctx, AsyncCallback cb,
object extraData)
{
this.ctx = ctx;
this.cb = cb;
this.extraData = extraData;
}

internal HttpContext ctx;
internal AsyncCallback cb;
internal object extraData;
private bool isCompleted = false;
private ManualResetEvent callCompleteEvent = null;

internal void CompleteRequest()
{
isCompleted = true;

lock (this)
{
if (callCompleteEvent != null)
{
callCompleteEvent.Set();
}
}
}

// IAsyncResult
//
public object AsyncState { get { return (extraData); } }
public bool CompletedSynchronously { get { return (false); } }
public bool IsCompleted { get { return (isCompleted); } }

public WaitHandle AsyncWaitHandle
{
get
{
lock (this)
{
if (callCompleteEvent == null)
{
callCompleteEvent = new ManualResetEvent(false);
}

return (callCompleteEvent);
}
}
}
}


}
}

Thanks in advance for your help.
 
Ad

Advertisements

J

Jesse Houwing

Hello Alphapage,

My guess is that it's not the page you're waiting for, but the lock on the
session state. Try disabling the session state for Default.aspx by adding
the following to the @Page directive like this:

<%@ Page language="c#" Codebehind="Default.aspx.cs"
AutoEventWireup="false" Inherits="Default
EnableSessionState="false" %>

Every request within the same session needs to wait for the previous page
to complete redering up to a certain point at which the session is released.

So if you disable the session, or set it to readonly you shouldn't have this
problem.

Jesse

Hello,

You can find my AsyncPage class which inherits from Page and
IHttpAsyncHandler.
I inherit my default.aspx page from AsyncPage and put a linkbutton on
that
page and set the PostbackUrl property to
http://localhost:port/default.aspx?test=1
I run my app, the page is displayed (no problem), I click the
linkbutton
(the page sleeps during 20000ms, no problem).
The problem is if I open second tab in Internet Explorer or Firefox
and go
to http://localhost:port/default.aspx when the first is still
sleeping, the
second tab freezes.
It seems the Asp.Net ThreadPool thread used by the first tab is
locked and
not sent back to the Asp.Net ThreadPool as it should be. So, the
second tab
is pushed in the queue of this strange waiting thread and freezes
until the
first tab finished sleeping.
How can I bypass this trouble ? (ie: I know all about Asynchrounous
pages in
Asp.Net 2.0, but I want to implement my own threadpool)
My code seems good and is an example of:
http://msdn.microsoft.com/msdnmag/issues/03/06/Threading/default.aspx
Here is my AsyncPage class:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Threading;
namespace WebApplicationThreadPool
{
public class AsyncPage3: Page,IHttpAsyncHandler
{
static protected DevelopMentor.ThreadPool _threadPool;
static AsyncPage3()
{
_threadPool =
new DevelopMentor.ThreadPool(2, 25, "AsyncPool");
_threadPool.PropogateCallContext = true;
_threadPool.PropogateThreadPrincipal = true;
_threadPool.PropogateHttpContext = true;
_threadPool.Start();
}
public new void ProcessRequest(HttpContext ctx)
{
// not used
}
public new bool IsReusable
{
get { return false; }
}
#region IHttpAsyncHandler Members

public IAsyncResult BeginProcessRequest(HttpContext context,
AsyncCallback cb, object extraData)
{
context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest
called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
AsyncRequestState reqState =
new AsyncRequestState(context, cb, extraData);
_threadPool.PostRequest(
new
DevelopMentor.WorkRequestDelegate(ProcessRequest),
reqState);
context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest
called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
return reqState;

}

public void EndProcessRequest(IAsyncResult result)
{
AsyncRequestState reqState = (AsyncRequestState)result;
reqState.ctx.Response.Output.Write("IHttpAsyncHandler.EndProcessReques
t called on thread {0}<br/>",

AppDomain.GetCurrentThreadId());
}
#endregion

void ProcessRequest(object state, DateTime requestTime)
{
AsyncRequestState reqState = state as AsyncRequestState;
if (reqState.ctx.Request.QueryString["test"]=="1")
Thread.Sleep(20000);
// Synchronously call base class Page.ProcessRequest
// as you are now on a thread pool thread.
base.ProcessRequest(reqState.ctx);
reqState.ctx.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequ
est
called on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
//Thread.Sleep(20000);
// This triggers the asp.net plumbing to call our
// IHttpAsyncHandler.EndProcessRequest method.
//
reqState.CompleteRequest();
reqState.cb(reqState);
}
public class AsyncRequestState : IAsyncResult
{
public AsyncRequestState(HttpContext ctx, AsyncCallback
cb,
object extraData)
{
this.ctx = ctx;
this.cb = cb;
this.extraData = extraData;
}
internal HttpContext ctx;
internal AsyncCallback cb;
internal object extraData;
private bool isCompleted = false;
private ManualResetEvent callCompleteEvent = null;
internal void CompleteRequest()
{
isCompleted = true;
lock (this)
{
if (callCompleteEvent != null)
{
callCompleteEvent.Set();
}
}
}
// IAsyncResult
//
public object AsyncState { get { return (extraData); } }
public bool CompletedSynchronously { get { return (false);
} }
public bool IsCompleted { get { return (isCompleted); } }
public WaitHandle AsyncWaitHandle
{
get
{
lock (this)
{
if (callCompleteEvent == null)
{
callCompleteEvent = new
ManualResetEvent(false);
}
return (callCompleteEvent);
}
}
}
}
}
}
Thanks in advance for your help.
 
Ad

Advertisements


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top