问题
I'm trying to implement an HttpStreaming comet push server in ASP.net. I am implementing an IHttpAsyncHandler that holds onto an http request and periodically sends messages down to the connected client. The connection with the client can be held open for a very long time (lets say 30 minutes). The issue that I am having is that since I don't end the request for a very long time, the handler technical is still running. So when the app pool recycles or ends, my asp.net application doesn't end gracefully. Meaning, Application_End never gets called in Global.asax since it is waiting for all handlers to complete before it gets called. My handler hasn't completed yet since it is holding on to the request. Eventually, the application just gets killed by IIS.
Here a sample HttpHandler that runs infinitely until something tells it to stop.
public class StreamingSocketHandler3 : IHttpHandler
{
private static readonly AppDomainShutdown Instance = AppDomainShutdown.Instance;
public void ProcessRequest(HttpContext context)
{
long c = 1;
bool stop = false;
Instance.OnStop += delegate()
{
stop = true;
};
while (!stop)
{
LogThis.Log.LogThis("loop: " + c, LogThis.eloglevel.debug);
c++;
System.Threading.Thread.Sleep(1000);
}
}
public bool IsReusable
{
get
{
return true;
}
}
}
If a client connects to this handler and then I stop the app pool, the web app doesn't end until the app gets completely killed by IIS sometime later.
The obvious answer to this problem is to listen to some sort of application end event and then end the request. I can't hook into Global.asax Application_end as it doesn't get called until the handler ends. The following blog post (link) provides some other alternatives (see q5 at the end of the post). I have tried the AppDomain.DomainUnload event suggest with no luck. I have also tried the IRegisteredObject interface suggested. That doesn't work either. I have built the following class that implements IRegisteredObject for testing.
public sealed class AppDomainShutdown : IRegisteredObject
{
public event Action OnStop;
// Singleton reference
public static readonly AppDomainShutdown Instance = new AppDomainShutdown();
// Singleton private Constructor
private AppDomainShutdown()
{
// Register the object
HostingEnvironment.RegisterObject(this);
}
public void Stop(bool immediate)
{
// Whats it want us to do?
if (!immediate)
{
// Do some code to handle graceful
// if OK
LogThis.Log.LogThis("Not Immediate Stop called", LogThis.eloglevel.debug);
OnStop();
HostingEnvironment.UnregisterObject(this);
}
else
{
// Do some code to force down (THREAD.ABORT)
// Mandatory
LogThis.Log.LogThis("Immediate Stop called", LogThis.eloglevel.debug);
OnStop();
HostingEnvironment.UnregisterObject(this);
}
}
}
If I make a call to this class from Global.asax without the handler starting, I get the application stop notification as expected. However, placing the same call in the HttpHandler (see the handler code), the OnStop event never fires.
What's frustrating is that I have seen a couple of forums posts on the web were the posts had my exact issue and the poster supposedly was able to implement IRegisteredObject and end the HttpRequest so the app could shutdown.
Please note that the HttpHandler code I'm presenting is simply for testing that I can end the ProcessRequest method in response to the application ending.
来源:https://stackoverflow.com/questions/7747312/asp-net-httphandler-long-running-processrequest-doesnt-end-on-app-recycle