ASP.net HttpHandler длительный процесс запроса не завершается при переработке приложения

#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 — в качестве альтернативы, может быть, вы могли бы реализовать деструктор ~ для достижения того же эффекта (при условии, что у вас есть ресурсы для очистки)?