我试图在ASP.net中实现HttpStreaming彗星推送服务器。我正在实现一个IHttpAsyncHandler,它保留一个http请求并定期向连接的客户端发送消息。与客户的连接可以保持打开很长时间(比方说30分钟)。我遇到的问题是,由于我很长时间没有结束请求,因此处理程序技术仍在运行。因此,当应用程序池回收或结束时,我的asp.net应用程序不会优雅地结束。意思是,Application_End永远不会在Global.asax中调用,因为它在调用之前等待所有处理程序完成。我的处理程序尚未完成,因为它正在保留请求。最终,该应用程序刚刚被IIS杀死。
这里有一个无限运行的示例HttpHandler,直到某些东西告诉它停止。
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;
}
}
}
如果客户端连接到此处理程序,然后我停止了应用程序池,则Web应用程序不会结束,直到该应用程序稍后被IIS完全杀死。
这个问题的明显答案是听取某种应用程序结束事件然后结束请求。我无法挂钩到Global.asax Application_end,因为在处理程序结束之前它不会被调用。以下博客文章(link)提供了一些其他选择(请参阅帖子末尾的q5)。我已经尝试过AppDomain.DomainUnload事件建议没有运气。我也尝试过建议的IRegisteredObject接口。这也不起作用。我构建了以下类来实现IRegisteredObject以进行测试。
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);
}
}
}
如果我在没有处理程序启动的情况下从Global.asax调用此类,我会按预期获得应用程序停止通知。但是,在HttpHandler中放置相同的调用(请参阅处理程序代码),OnStop事件永远不会触发。
令人沮丧的是,我在网上看到了几个论坛帖子,帖子有我的确切问题,据说海报能够实现IRegisteredObject并结束HttpRequest,以便应用程序可以关闭。
请注意,我提供的HttpHandler代码仅用于测试我可以结束ProcessRequest方法以响应应用程序结束。