如何解决请求超时的HttpException异常 (ASP.NET 2.0 32-bit)


注意:下列的步骤适用于ASP.NET 2.0(32 bit) 。没有测试过其他版本的ASP.NET。

症状

========

应用事件记录里可能出现下方的警告文字:

这种问题基本上发生在当ASP.NET的服务器端执行请求的时间超过所允许的最大时间之时。

最大超时时间可以在配置文件的httpRuntime元素的executionTimeout属性中设置。(在.Net 2.0中,默认值是110秒

如何重现

===============

创建一个ASPX页面,命名为sleep.aspx。它将睡眠20秒:

<%@ Page Language=”C#” %>

<%@ import Namespace=”System.Diagnostics” %>

<script runat=”server”>

protected void Page_Load(object sender, EventArgs e)

{

DateTime time = DateTime.Now;

Response.Write(String.Format(“Time: {0}:{1}:{2}”, time.Hour, time.Minute, time.Second) +

“\tCurrent process: ” + Process.GetCurrentProcess().Id.ToString());

Response.Write(“<BR>”);

Response.Write(String.Format(“This application is running in {0}”, System.Environment.Version.ToString()));

System.Threading.Thread.Sleep(20000);

}

</script>

<html>

<head>

<title>ASP.NET Simple Page</title>

</head>

<body bgcolor=”#FFFFFF”>

<p><asp:label id=”Message” runat=”server” /></p>

</body>

</html>

创建一个web.config文件,将其放在与sleep.aspx同一目录下。在此文件中设置最大超时时间为5秒。

<?xml version=”1.0″ encoding=”UTF-8″?>

<configuration>

<system.web>

<httpRuntime executionTimeout=”5″/>

</system.web>

</configuration>

使用你的浏览器访问sleep.aspx,过一会儿你就将收到错误信息:“[HttpException (0x80004005): Request timed out.]”。相关的警告信息也将出现在事件日志里。

注意:

你可能发现这个错误信息——“[HttpException (0x80004005): Request timed out.]”——并没有在5秒后立即出现。ASP.NET在内部使用一个定时器(System.Threading.Timer 的一个实例)来调用取消请求的操作。这个定时器15秒触发一次。因此实际上请求可能在5秒到20秒之间的任意时间发生超时。

请参考

http://blogs.msdn.com/b/pedram/archive/2007/10/02/how-the-execution-timeout-is-managed-in-asp-net.aspx

如何捕获“[HttpException (0x80004005): Request timed out.]”的转储文件

===============================================================

当发生HttpException异常时,人们常犯的一种*错误*是设置一个debugger来监视HttpException异常,并生成转储文件。

实际上当发生请求超时之时,ASP.NET尽管显示给用户看地是HttpException,但是抛出的是ThreadAbortExceptiony异常。

为所有ThreadAbortException异常生成转储文件是不可行的。为了解决这个问题,我们必须在ThreadAboutException异常被抛出设定断点。

我用如下的步骤来捕获错误信息“[HttpException (0x80004005): Request timed out.]”的转储文件。

将下方的文本保存成aspnet_timeout.cfg,放在c:\目录下。

<ADPlus Version=’2′>

<!– Configuring ADPlus to log all first chance exceptions –>

<!– Will still create full dump for any type of second chance exceptions –>

<KeyWords>

<keyword Name=”loadbysos”> .loadby sos mscorwks </keyword>

<keyword Name=”GetJIT”> !name2ee System.web.dll System.Web.RequestTimeoutManager.CancelTimedOutRequests </keyword>

<keyword Name=”JITAddress”> .foreach /pS 0n12 ( record {!name2ee System.web.dll System.Web.RequestTimeoutManager.CancelTimedOutRequests}) { r $t1= ${record}; bp $t1+0x172 “.dump /ma /u ${AdpDumpDirEsc}\\Full Request timed out ${AdpProcName}_.dmp;g”; .printf”*breakpoint list*\n”; bl} </keyword>

</KeyWords>

<Settings>

<Option> NoDumpOnFirst </Option>

<RunMode> CRASH </RunMode>

</Settings>

<PreCommands>

<DebugActions> loadbysos; GetJIT; JITAddress </DebugActions>

</PreCommands>

</ADPlus>

用*管理员权限*打开命令行,转到Windows的Debugging工具的安装目录(默认路径为%programfiles%\Debugging Tools for Windows (x86))

运行以下命令:

%windir%\system32\inetsrv\appcmd list wp

你将得到发生问题的应用池的工作进程的PID。

然后运行以下命令:

adplus.exe -c c:\aspnet_timeout.cfg -o <output folder> -p <pid of problematic apppool>

其中<output foder>是你想存放转储文件的存在的目录。

这样就会跳出一个cdb.exe窗口。请保持改窗口运行,因为它将会检测有问题的应用池。如果发生“请求超时”,他就会自动生成转储文件.

如何通过转储文件找到是哪个操作引发的“请求超时”

===========================================================

使用windbg打开转储文件。然后加载sos

0:025> .loadby sos mscorwks

转储(dump)当前线程堆里的所有对象,你将发现System.Threading.Thread对象:

0:025> !dso

OS Thread Id: 0x444 (25)

ESP/REG Object Name

eax 05baf5b0 System.Threading.Thread

ebx 05baf5b0 System.Threading.Thread

ecx 01c4f300 System.Web.RequestTimeoutManager+RequestTimeoutEntry

esi 01c4f300 System.Web.RequestTimeoutManager+RequestTimeoutEntry

0f1ff03c 05b33ad4 System.Web.Util.DoubleLinkList

0f1ff040 01c4b508 System.Collections.ArrayList

0f1ff044 05b3397c System.Web.RequestTimeoutManager

0f1ff064 01c4aa94 System.Threading.ContextCallback

0f1ff068 05b3397c System.Web.RequestTimeoutManager

0f1ff088 05b33b30 System.Threading._TimerCallback

0f1ff094 01c4b4e4 System.Threading.ExecutionContext

0f1ff0a0 01c4b4e4 System.Threading.ExecutionContext

0f1ff0a4 05b33b30 System.Threading._TimerCallback

0f1ff0b0 05b33b30 System.Threading._TimerCallback

0f1ff1c0 01c4b090 System.Collections.Hashtable+HashtableEnumerator

0f1ff25c 05b33b30 System.Threading._TimerCallback

0f1ff260 05b33b30 System.Threading._TimerCallback

转储(Dump) System.Threading.Thread对象中的信息,你将找到DONT_USE_InternalThread字段:

0:025> !do 05baf5b0

Name: System.Threading.Thread

MethodTable: 0e3c10f8

EEClass: 0e17d994

Size: 56(0x38) bytes

(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

Fields:

MT Field Offset Type VT Attr Value Name

0e3b1f08 400063f 4 ….Contexts.Context 0 instance 05b20528 m_Context

0e3bd818 4000640 8 ….ExecutionContext 0 instance 01c4d2c8 m_ExecutionContext

0e3c0b24 4000641 c System.String 0 instance 00000000 m_Name

0e3c0f88 4000642 10 System.Delegate 0 instance 00000000 m_Delegate

0e3ba220 4000643 14 System.Object[][] 0 instance 00000000 m_ThreadStaticsBuckets

0e3c2cc0 4000644 18 System.Int32[] 0 instance 00000000 m_ThreadStaticsBits

0e3c3720 4000645 1c …ation.CultureInfo 0 instance 00000000 m_CurrentCulture

0e3c3720 4000646 20 …ation.CultureInfo 0 instance 00000000 m_CurrentUICulture

0e3c0740 4000647 24 System.Object 0 instance 00000000 m_ThreadStartArg

0e3c33ec 4000648 28 System.IntPtr 1 instance 1915fa8 DONT_USE_InternalThread

0e3c2d70 4000649 2c System.Int32 1 instance 2 m_Priority

0e3c2d70 400064a 30 System.Int32 1 instance 5 m_ManagedThreadId

0e399740 400064b 16c …LocalDataStoreMgr 0 shared static s_LocalDataStoreMgr

运行 !threads 命令列出所有线程,你将发现与引发“请求超时”有关的线程(它的操作系统线程ID是dd4):

0:025> !threads

ThreadCount: 7

UnstartedThread: 0

BackgroundThread: 7

PendingThread: 0

DeadThread: 0

Hosted Runtime: no

PreEmptive GC Alloc Lock

ID OSID ThreadOBJ State GC Context Domain Count APT Exception

8 1 1400 018ad710 8220 Enabled 05baea40:05baf074 018ac928 0 Ukn

19 2 132c 018b8658 b220 Enabled 00000000:00000000 018ac928 0 MTA (Finalizer)

22 3 16ec 018d7718 80a220 Enabled 00000000:00000000 018ac928 0 MTA (Threadpool Completion Port)

23 4 830 018d7ee8 1220 Enabled 00000000:00000000 018ac928 0 Ukn

24 5 dd4 01915fa8 380b220 Enabled 01c57b44:01c58fe8 018d8590 1 MTA (Threadpool Worker)

25 6 444 01923d00 180b220 Disabled 01c4b604:01c4d008 018d8590 0 MTA (Threadpool Worker)

14 7 180 01933348 880a220 Enabled 00000000:00000000 018ac928 0 MTA (Threadpool Completion Port)

切换到那个有问题的线程,列出调用栈。你将发现sleep函数:

0:025> ~~[dd4]s

eax=0000002d ebx=00000000 ecx=00004e20 edx=00000000 esi=0edced40 edi=00000000

eip=777f96f4 esp=0edcecfc ebp=0edced64 iopl=0 nv up ei pl nz na po nc

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202

ntdll!KiFastSystemCallRet:

777f96f4 c3 ret

0:024> !clrstack

OS Thread Id: 0xdd4 (24)

ESP EIP

0edcee4c 777f96f4 [HelperMethodFrame: 0edcee4c] System.Threading.Thread.SleepInternal(Int32)

0edceea0 015806e1 ASP.sleep_aspx.Page_Load(System.Object, System.EventArgs)

0edceedc 6d59a7ff System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)

0edceeec 62562544 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)

0edcef00 6255ba44 System.Web.UI.Control.OnLoad(System.EventArgs)

0edcef14 6255ba83 System.Web.UI.Control.LoadRecursive()

0edcef2c 62557b34 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)

0edcf084 62557764 System.Web.UI.Page.ProcessRequest(Boolean, Boolean)

0edcf0bc 62557691 System.Web.UI.Page.ProcessRequest()

0edcf0f4 62557626 System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)

0edcf100 62557602 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)

0edcf114 01580455 ASP.sleep_aspx.ProcessRequest(System.Web.HttpContext)

0edcf118 6255dad6 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()

0edcf14c 6253132c System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)

0edcf18c 62b2583f System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)

0edcf190 62b1b96c [InlinedCallFrame: 0edcf190]

0edcf230 62b06071 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)

0edcf2a0 62bdb5e6 System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)

0edcf2a4 62bdb7d7 [InlinedCallFrame: 0edcf2a4]

0edcf7f8 005522b4 [NDirectMethodFrameStandalone: 0edcf7f8] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)

0edcf808 62bdb67d System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)

0edcf88c 62bdb7d7 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)

0edcf98c 005522b4 [ContextTransitionFrame: 0edcf98c]

Xinjin from APAC DSI

 

Comments (2)

  1. Anonymous says:

    好文, 顶起!

    补充一下, 文中"adplus.exe -c c:aspnet_timeout.cfg -o <output folder> -p <pid of problematic apppool>" 的部分应该添加上-crash, 为adplus指定运行模式, 没有这个adplus不让运行的.

  2. yunlong,because config file explicitly set

    <RunMode> CRASH </RunMode>

    Thus we dont need to input -crash here

Skip to main content