2016-08-02 6 views
0

У меня есть HttpHandler, который выглядит следующим образом:C# HttpHandler сбой IIS - но только в режиме выпуска с оптимизациями

public class GoodIISHandler : IHttpHandler 
{ 
    public void ProcessRequest(HttpContext context) 
    { 
     try 
     { 
      try 
      { 
       context.Response.End(); 
      } 
      catch (Exception) 
      { 
      } 
     } 
     finally 
     { 
      Console.WriteLine("Inside finally block"); 
     } 
    } 

    public bool IsReusable => true; 
} 

Он отлично работает! За исключением случаев, когда они скомпилированы в режиме деблокирования с включенными и затем выполненными оптимизациями (в Windows Server 2012 выполняется IIS 8 с .NET 4.5.2). Затем он сбрасывает IIS.

Произошло необработанное исключение, и процесс был прекращен.

ID приложения:/LM/W3SVC/1592535739/ROOT/HttpHandlerApp

Идентификатор процесса: 648

Исключение: System.Threading.ThreadAbortException

Сообщение: Тема была быть прервана.

StackTrace: в System.Web.HttpRuntime.ProcessRequestNotificationPrivate (IIS7WorkerRequest сог, HttpContext контекст)

на System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper (IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 флаги)

в System.Web.Hosting.PipelineRuntime.ProcessRequestNotification (IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 флаги)

и

Faulting Имя приложения: w3wp.exe, версия: 8.0.9200.16384, штамп времени: 0x50108835

Faulting имя модуля: KERNELBASE.dll, версия: 6.2.9200.17366, штамп времени: 0x554d4531

код исключения: 0xe0434352

Неисправность смещения: 0x000000000004aea8

Сбойное идентификатор процесса: 0x288

Сбойное время запуска приложения: 0x01d1ec2c7db735a6

Faulting путь приложения: C: \ WINDOWS \ system32 \ Inetsrv \ w3wp.exe

Faulting путь модуля: C: \ Windows \ system32 \ KERNELBASE.dll

Отчет Id: bb7471fa-581f-11e6-93f1-00155d461b1c

Сбойного пакет полное наименование:

Сбойного пакет-относительный идентификатор приложения:

Я сузил проблему до определенного бита IL, который изменяется, когда оптимизация включена/отключена.

Вот IL для ProcessRequest, который не откажет IIS:

.method public hidebysig newslot virtual final 
     instance void ProcessRequest(class [System.Web]System.Web.HttpContext context) cil managed 
{ 
    // Code size  30 (0x1e) 
    .maxstack 1 
    .try 
    { 
    .try 
    { 
     IL_0000: ldarg.1 
     IL_0001: callvirt instance class [System.Web]System.Web.HttpResponse [System.Web]System.Web.HttpContext::get_Response() 
     IL_0006: callvirt instance void [System.Web]System.Web.HttpResponse::End() 
     IL_000b: leave.s IL_0010 

    } // end .try 
    catch [mscorlib]System.Exception 
    { 
     IL_000d: pop 
     IL_000e: leave.s IL_0010 

    } // end handler 
    IL_0010: leave.s IL_001d 

    } // end .try 
    finally 
    { 
    IL_0012: ldstr  "Inside finally block" 
    IL_0017: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_001c: endfinally 
    } // end handler 
    IL_001d: ret 
} // end of method GoodIISHandler::ProcessRequest 

Чтобы сбой IIS, изменение линия 19 в

 IL_000e: leave.s IL_001d 

Это изменение делает вложенный выход поймать блок непосредственно к метод возвращает команду без посещения одной команды, оставшейся в блоке try try..finally.

Моя гипотеза заключается в том, что авария связана с магическим режимом автоматического реверберации ThreadAbortException (один из которых выдает context.Response.End()) и как это управляет CLR и/или IIS и/или ASP.NET; и поэтому, когда оптимизированный ИЛ выходит из блока catch непосредственно в инструкцию возврата, возникает некоторая гипотетическая ошибка сброса, которую CLR/IIS/ASP.NET пробивает в IL_0010, и пропустил ThreadAbortException весь IIS.

Есть ключи разбросаны по всему интернету об этом поведении (например these msdn docs состояния ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. и this blog упоминает ... notably ASP.NET, even aborts individual threads routinely without unloading the domain. They backstop the ThreadAbortExceptions, call ResetAbort on the thread and reuse it or return it to the CLR ThreadPool.), но я не могу найти ничего конкретного о механизме.

Итак, я думаю, мой вопрос: что здесь происходит? Действительно ли я обнаружил ошибку CLR или IIS или ASP.NET, чтобы этот механизм прерывания потока был побежден оптимизацией IL?

Полностью оформленный в стиле репродукции можно найти по адресу https://github.com/jamezor/HttpHandlerRepro для всех, кто интересуется.

+0

Какую версию .NET Framework вы использовали? Как известно, у 4.6.0 есть некоторые проблемы, и вы должны отключить RyuJIT для обхода некоторых. –

+0

Мы работаем с .NET 4.5.2, поэтому не можем винить 4.6, к сожалению :) – Jamezor

ответ

0

Не используйте response.end() прекратить обработку запроса, то лучше использовать HttpApplication.CompleteRequest(). Посмотрите на эти посты:

+0

Это может быть правдой, но тогда все равно 'Response.End()' не должен разрушать рабочий процесс. – CodeCaster

+0

Да, это правда: - /. Хорошо, и вы проверили настройки быстрой проверки отказов для пула приложений в IIS? Имеются ли значения по умолчанию? Любое другое интересное событие в журнале событий? – Plaz

+0

Мы перенесли 200k строк из Delphi.Net в C#, Response.End() используется либерально, к сожалению. Но в любом случае, только с одним небольшим изменением IL (или просто компиляцией без оптимизаций) IIS работает так, как ожидалось, и не падает, что для меня исключает любые возможные проблемы с конфигурацией. И в этом вопросе показаны только события в журнале событий, другие не отображаются. – Jamezor