ASP.net HttpHandler долгое время ProcessRequest не заканчивается при перезапуске приложения - PullRequest
3 голосов
/ 13 октября 2011

Я пытаюсь реализовать кометный сервер 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 в ответ на завершение работы приложения.

...