Я пытаюсь реализовать кометный сервер HttpStreaming в ASP.net. Я реализую 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;
}
}
}
Если клиент подключается к этому обработчику, а затем я останавливаю пул приложений, веб-приложение не закрывается, пока приложение не будет полностью уничтожено IIS через некоторое время.
Очевидный ответ на эту проблему - прослушивание какого-либо события завершения приложения, а затем завершение запроса. Я не могу подключиться к Global.asax Application_end, так как он не вызывается, пока не закончится обработчик. Следующий пост в блоге ( ссылка ) предоставляет некоторые другие альтернативы (см. 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 в ответ на завершение работы приложения.