#c# #asp.net #httphandler
#c# #asp.net #httphandler
Вопрос:
Я пытаюсь реализовать HttpStreaming comet push-сервер в 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 некоторое время спустя.
Очевидный ответ на эту проблему — прослушать какое-то событие завершения приложения, а затем завершить запрос. Я не могу подключиться к глобальному.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 в ответ на завершение работы приложения.
Комментарии:
1. просто идея — но поможет ли в этом случае использование шаблона IDisposable? (Я даже не уверен, как вы могли бы …), но использование оператора «using» приведет к отсрочке уничтожения объекта. Net, в отличие от IIS — в качестве альтернативы, может быть, вы могли бы реализовать деструктор ~ для достижения того же эффекта (при условии, что у вас есть ресурсы для очистки)?