我正在尝试在 ASP.net 中实现 HttpStreaming comet 推送服务器。我正在实现一个 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 http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx)提供了一些其他替代方案(请参阅帖子末尾的 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 方法以响应应用程序结束。