1

我在重写的 Page OnUnload 中运行一个方法,但前提是 Page_PreRender 方法已运行。

显然,当我在 Page_PreRender 中时,我可以翻转一个类级别的布尔值并在 OnUnload 中检查它,但如果有更内在的方法来判断 Page_PreRender 是否已运行,我想使用它。

有任何想法吗?

感谢您的任何想法。

更新:让我稍微改一下我的问题。我正在寻找是否存在页面生命周期中固有的简单方法的答案,也许是由 ASP.Net 框架设置的属性,也许是其他东西,在 Page_PreRender 运行后与 Page_PreRender 运行时不同不跑。

我目前在 Page_PreRender 中设置一个布尔值来告诉我它是否已经运行。它有效,但如果有一种方法可以在不添加额外布尔检查的情况下完成相同的事情,我不喜欢这个解决方案。如果可能的话,创建在 Page_PreRender 期间触发的事件与我想避免的冗余级别相同。

4

7 回答 7

3

您提到(在您对另一篇文章的评论中)您的问题在调用 Response.Redirect() 时会表现出来,因为它会引发 ThreadAbortException,这会导致您的 OnPreRender() 事件未被调用。那么为什么不使用它呢?:

Response.Redirect("~/SomePage.aspx", false);

您在此处看到的“false”表示页面的执行是否应该立即终止。默认情况下,Response.Redirect() 使用“true”。如果您需要运行 OnPreRender() 事件以便 OnLoad() 事件拥有所需的一切,则将其设置为“false”并确保在调用 Response.Redirect 后跳转到 Page_Load() 的末尾() 或者在它可以运行之后执行的代码。

也许你不喜欢使用重载的 Response.Redirect() 方法传递“false”的想法,所以这就是你没有走那条路的原因。以下是一些可能有助于改变您想法的文档:

Microsoft 声明“建议为 endResponse 参数传递 false ”,因为指定“true”会调用 HttpResponse。原始请求的End() 方法,然后在完成时抛出 ThreadAbortException。微软接着说“这个例外对 Web 应用程序的性能有不利影响”。请参阅此处的“备注”部分:http: //msdn.microsoft.com/en-us/library/a8wa7sdt.aspx

这是去年在 MSDN 上发布的:

End 方法也在我的“从不使用”列表中。停止请求的最好方法是调用 HttpApplication.CompleteRequest。End 方法之所以存在,是因为我们在 1.0 发布时尝试与经典 ASP 兼容。经典 ASP 具有终止 ASP 脚本处理的 Response.End 方法。为了模仿这种行为,ASP.NET 的 End 方法尝试引发 ThreadAbortException。如果这成功了,调用线程将被中止(非常昂贵,对性能不利)并且管道将跳转到 EndRequest 事件。ThreadAbortException,如果成功,当然意味着线程在它可以调用更多代码之前展开,所以调用 End 意味着你不会在此之后调用任何代码。如果 End 方法不能引发 ThreadAbortException,相反,它会将响应字节刷新到客户端,但它会同步执行此操作,这对性能非常不利,并且当 End 之后的用户代码执行完毕时,管道会跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并使用 56k 调制解调器,因此最好异步发送字节,这是我们在请求结束时正常方式所做的事情。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。但它是同步执行的,这对性能非常不利,并且当 End 之后的用户代码执行完毕时,管道会跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并使用 56k 调制解调器,因此最好异步发送字节,这是我们在请求结束时正常方式所做的事情。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。但它是同步执行的,这对性能非常不利,并且当 End 之后的用户代码执行完毕时,管道会跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并使用 56k 调制解调器,因此最好异步发送字节,这是我们在请求结束时正常方式所做的事情。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。管道跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并使用 56k 调制解调器,因此最好异步发送字节,这是我们在请求结束时正常方式所做的事情。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。管道跳转到 EndRequest 通知。向客户端写入字节是一项非常昂贵的操作,特别是如果客户端在地球的另一端并且使用 56k 调制解调器,因此最好异步发送字节,这是我们在请求结束时以正常方式执行的操作。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。这是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。这是我们在请求以正常方式结束时所做的。同步刷新真的很糟糕。总而言之,您不应该使用 End,但使用 CompleteRequest 非常好。End 的文档应该说明 CompleteRequest 是跳到 EndRequest 通知并完成请求的更好方法。

正如 MSDN 建议的那样,我在调用 Response.Redirect() 后添加了这一行,并注意到一切似乎都运行相同。不确定 4.0 是否需要它,但我认为这不会造成伤害:

HttpContext.Current.ApplicationInstance.CompleteRequest();

更新 1

在对 Response.Redirect() 的调用中使用“false”可以避免 ThreadAbortException,但是可能在您的页面上抛出的其他未处理异常呢?这些异常仍然会导致您在没有 OnPreRender() 的情况下调用 OnUnload() 的问题。您可以按照每个人的建议在 OnPreRender() 中使用一个标志来避免这种情况,但是如果您抛出未处理的异常,您就会遇到更大的问题,并且无论如何都应该重定向到错误页面。由于未处理的异常不是您计划在每次回发时抛出的东西,因此如果您将 OnUnload() 逻辑包装在 Try-Catch 中会更好。如果您正在记录和监视您的异常,您将看到在 OnUnload() 事件中记录 NullReference 异常之前引发了一个未处理的异常,并且会知道要忽略哪个异常。

更新 2

您仍然应该将 OnUnload() 包装在 Try-Catch 中,但我认为这就是您真正想要的(记住 IsRequestBeingRedirected 将在调用 Response.Redirect 或在未处理异常后重定向到错误页面时为真) .:

if (HttpContext.Current.Response.IsRequestBeingRedirected != true)
{
    //You're custom OnUnload() logic here.
}

有了这个,您将知道在 OnUnload() 事件中处理您的自定义逻辑是否安全(甚至值得)。我意识到我可能应该开始这样做,但我认为我们今天学到了很多。;)

注意:使用 Server.Transfer() 也会调用可怕的 Response.End()。为避免这种情况,请改用将preserveForm属性设置为“false”的 Server.Execute():

Server.Execute("~/SomePage.aspx", false);
return;

注意:关于 Server.Execute("~/SomePage.aspx", false); 的事情 是 IsRequestBeingRedirected 将是错误的,但您的 OnPreRender() 仍将执行,所以不用担心。

于 2011-05-28T08:33:15.530 回答
1

答案是肯定的,您可以,但并非总是如此:) 根据反射代码,ScriptManager该类包含私有 bool 字段_preRenderCompleted,该字段true在处理内部IPage接口PagePreRenderComplete事件时设置为。您可以使用反射从ScriptManager.GetCurrent(page)结果对象中获取此字段

于 2011-05-31T07:32:16.520 回答
0

我不确定你到底是什么意思。根据ASP.NET 页面生命周期 PreRender总是在Unload. 如果您在此PreRender事件中执行一些 if 条件,并且您想测试Unload是否满足条件,则页面类上的布尔字段似乎是个好主意。

于 2011-05-19T16:35:55.850 回答
0

将 trace=true 添加到页面指令。

于 2011-05-19T16:36:03.403 回答
0

在 PreRender 事件处理程序中设置一个布尔字段,然后检查它是否在 Unload 事件处理程序中设置。

于 2011-05-24T18:21:02.450 回答
0

创建在 PreRender 事件中触发的自定义事件。

于 2011-05-24T19:28:56.503 回答
0

我认为没有存储任何类型的状态,因为 ASP.NET 引擎并不真正需要它,因为它隐含地知道它的状态。

使用 .NET Reflector 搜索,页面呈现事件似乎是从这个内部 System.Web.UI.Page 方法引发的:

private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)

你可以看看它,没有状态的概念。您可以获得的唯一信息是跟踪。如果您有权访问 Unload 事件,那么您应该有权访问跟踪吗?或者我想念一些东西:-)

由于跟踪实际上是一个隐藏的数据集(请参阅我的答案:将 Trace.axd 中的数据记录到 text/xml 文件中),您也许可以获得信息。但是不建议在生产中设置 trace=true ......

于 2011-05-28T07:18:05.130 回答