2016-08-02 30 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; 
} 

它的伟大工程!除了在发布模式下编译并启用了优化并随后执行(在运行带有.NET 4.5.2的IIS 8的Windows Server 2012上)之外。然后它崩溃IIS。

发生未处理的异常,并且进程终止。

应用程序ID:/ LM/W3SVC/1592535739/ROOT/HttpHandlerApp

进程ID:648

例外:System.Threading.ThreadAbortException

消息:线程已被中止。

堆栈跟踪:在System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest WR,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标志)

错误的应用程序名:w3wp.exe,版本:8.0.9200.16384,时间戳:0x50108835

错误模块名称:KERNELBASE.dll,版本:6.2.9200.17366,时间戳:0x554d4531

异常代码:0xe0434352

故障偏移:0x000000000004aea8

出错进程ID:0x288

错误的应用程序的开始时间:0x01d1ec2c7db735a6

错误的应用程序路径:C:\ Windows \ System32下\ INETSRV \ w3wp.exe的

错误模块路径:C:\ Windows \ System32下\ KERNELBASE.dll

报告编号:bb7471fa-581f-11e6-93f1-00155d461b1c

断裂作用包全名:

断裂作用包相对应用程序ID:

我已经缩小了问题的范围,即在启用/禁用优化时更改的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 

这种变化直接使嵌套catch块退出到方法返回指令,而不访问try..finally的try块中剩余的单个指令。

我的假设是,崩溃与ThreadAbortException(其中一个context.Response.End()将抛出)的魔术自动重投行为有关,以及CLR和/或IIS和/或ASP.NET如何管理该行为;所以当优化的IL从catch块直接退出到返回指令时,在IL_0010处插入的CLR/IIS/ASP.NET错过了一些假想的中止重置魔术,并且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找到完全脚本的repro。

+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中的应用程序池的快速失败Proctection设置?有默认值吗?事件日志中的其他有趣事件? – Plaz

+0

我们已经从Delphi.Net迁移200k行到C#,不幸的是使用了Response.End()。但无论如何,只有一个微小的IL更改(或者只是编译没有优化),IIS按预期工作,并且不会崩溃,从而排除了任何可能的配置问题。事件日志中的唯一事件显示在问题中,没有其他人出现。 – Jamezor