如何判断Page_PreRender是否已经运行?

发布于 2024-11-08 00:45:36 字数 470 浏览 6 评论 0原文

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

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

有什么想法吗?

感谢您的任何想法。

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

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

I'm running a method in an overridden Page OnUnload, but only if the Page_PreRender method has run.

Obviously, I can flip a class-level bool when I'm in Page_PreRender and check it in OnUnload, but if there's a more intrinsic way to tell is Page_PreRender has run, I'd like to use that.

Any ideas?

Thanks for any thoughts.

UPDATE: Let me rephrase my question slightly. I'm looking for the answer to whether there is a simple way, inherent in the Page life cycle, perhaps a property that is set by the ASP.Net frameowork, perhaps something else, that is different after Page_PreRender has run versus when Page_PreRender has not run.

I am currently setting a boolean in Page_PreRender to tell me if it has run. It works, but I don't like this solution if there is a way to accomplish the same thing without adding the extra boolean check. Creating an event that fires during Page_PreRender is the same level of redundancy I'd like to avoid, if possible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

东北女汉子 2024-11-15 00:45:36

您提到(在另一篇文章的评论中)您的问题在调用 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。 Microsoft 继续表示“此异常会对 Web 应用程序性能产生不利影响”。请参阅此处的“备注”部分:http://msdn.microsoft.com/ en-us/library/a8wa7sdt.aspx

此内容已发布 去年在 MSDN 上:

End方法也是我的“从来没有
使用”列表。阻止的最好方法
请求是打电话
HttpApplication.CompleteRequest。这
End 方法之所以存在只是因为我们
尝试与经典兼容
ASP 1.0 发布时。经典的
ASP 有一个 Response.End 方法
终止 ASP 的处理
脚本。为了模仿这种行为,
ASP.NET 的 End 方法尝试引发
ThreadAbortException。如果这是
成功,调用线程将是
已中止(非常昂贵,不适合
性能)并且管道将
跳转到 EndRequest 事件。
ThreadAbortException,如果
成功,当然意味着
线程在调用任何之前展开
更多代码,因此调用 End 意味着您
之后将不会调用任何代码。
如果 End 方法无法引发
ThreadAbortException,它将
而是将响应字节刷新到
客户端,但它这样做
同步,这真的很糟糕
性能,以及当用户代码
End 执行完毕后,
管道向前跳转到 EndRequest
通知。将字节写入
客户端是一个非常昂贵的操作,
尤其是当客户半途而废时
世界各地并使用 56k
调制解调器,所以最好发送字节
异步,这就是我们所做的
当请求以正常方式结束时。
同步刷新确实很糟糕。
总而言之,你不应该使用
结束,但是使用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 异常之前抛出了未处理的异常,并且知道要忽略哪一个。因为您的 OnUnload() 将有一个 Try-Catch,所以它将安全地继续处理页面的其余部分,以便您可以按预期重定向到错误页面。

更新 2

您仍然应该将 OnUnload() 包装在 Try-Catch 中,但我认为这才是您真正想要的(记住 IsRequestBeingRedirected 在调用 Response.Redirect 或在 Unhandled 之后重定向到错误页面时将为 true例外)。:

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

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

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

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

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

You mention (in your comments on another post) that your problem manifests itself when calling Response.Redirect() because it throws a ThreadAbortException, which leads to your OnPreRender() event not being called. So why not use this instead?:

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

The "false" you see there indicates if execution of the page should terminate right there and then. By default, Response.Redirect() uses "true". If you need your OnPreRender() event to run so that your OnLoad() event will have everything it needs, then set it to "false" and just make sure you either jump to the end of your Page_Load() after calling Response.Redirect() or that the code that would execute after it is fine to run.

Maybe you don't like the idea of passing "false" using the overloaded Response.Redirect() method so that's why you didn't go that route. Here is some documentation that may help sway your mind:

Microsoft states that "passing false for the endResponse parameter is recommended" because specifying "true" calls the HttpResponse.End() method for the original request, which then throws a ThreadAbortException when it completes. Microsoft goes on to say that "this exception has a detrimental effect on Web application performance". See here in the "Remarks" section: http://msdn.microsoft.com/en-us/library/a8wa7sdt.aspx

This was posted last year on MSDN:

The End method is also on my “never
use” list. The best way to stop the
request is to call
HttpApplication.CompleteRequest. The
End method is only there because we
tried to be compatible with classic
ASP when 1.0 was released. Classic
ASP has a Response.End method that
terminates processing of the ASP
script. To mimic this behavior,
ASP.NET’s End method tries to raise a
ThreadAbortException. If this is
successful, the calling thread will be
aborted (very expensive, not good for
performance) and the pipeline will
jump ahead to the EndRequest event.
The ThreadAbortException, if
successful, of course means that the
thread unwinds before it can call any
more code, so calling End means you
won’t be calling any code after that.
If the End method is not able to raise
a ThreadAbortException, it will
instead flush the response bytes to
the client, but it does this
synchronously which is really bad for
performance, and when the user code
after End is done executing, the
pipeline jumps ahead to the EndRequest
notification. Writing bytes to the
client is a very expensive operation,
especially if the client is halfway
around the world and using a 56k
modem, so it is best to send the bytes
asynchronously, which is what we do
when the request ends the normal way.
Flushing synchronously is really bad.
So to summarize, you shouldn’t use
End, but using CompleteRequest is
perfectly fine. The documentation for
End should state that CompleteRequest
is a better way to skip ahead to the
EndRequest notification and complete
the request.

I added this line after calling Response.Redirect(), as MSDN suggests, and noticed everything appeared to run the same. Not sure if it's needed with 4.0, but I don't think it hurts:

HttpContext.Current.ApplicationInstance.CompleteRequest();

Update 1

Using "false" in the call to Response.Redirect() avoids the ThreadAbortException, but what about other Unhandled Exceptions that could be thrown on your page? Those exceptions will still cause your problem of OnUnload() being called without OnPreRender(). You can use a flag in OnPreRender() as everyone suggests to avoid this, but if you're throwing Unhandled Exceptions, you've got bigger problems and should be redirecting to an error page anyway. Since Unhandled Exceptions aren't something you plan to throw on every postback, it would be better if you wrapped your OnUnload() logic in a Try-Catch. If you're logging and monitoring your exceptions you will see that an Unhandled Exception was thrown right before logging a NullReference Exception in the OnUnload() event and will know which one to ignore. Because your OnUnload() will have a Try-Catch, it will safely continue processing the rest of the page so you can Redirect to the error page as expected.

Update 2

You should still have your OnUnload() wrapped in a Try-Catch, but I think this is what you're really looking for (remember IsRequestBeingRedirected will be true when calling Response.Redirect or when redirecting to an error page after an Unhandled Exception).:

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

With this, you will know if it is safe (or even worth it) to process your custom logic in the OnUnload() event. I realize I should have probably lead off with this, but I think we learned a lot today. ;)

NOTE: The use of Server.Transfer() will also call the dreaded Response.End(). To avoid this, use Server.Execute() with the preserveForm attribute set to "false" instead:

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

NOTE: The thing about Server.Execute("~/SomePage.aspx", false); is that IsRequestBeingRedirected will be false, but your OnPreRender() will still execute, so no worries there.

川水往事 2024-11-15 00:45:36

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

The answer is Yes, you can, but not always :)
According the Reflection code, the ScriptManager class contains the private bool field _preRenderCompleted, which is set to true while handling internal IPage interface PagePreRenderComplete event.
You can use the Reflection to get this field from ScriptManager.GetCurrent(page) resulting object

烟花易冷人易散 2024-11-15 00:45:36

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

I am not sure what exactly you mean by this. According to the ASP.NET Page Lifecycle PreRender always runs before Unload. If you perform some if condition inside this PreRender event and you would like to test in the Unload whether the condition was satisfied a boolean field on the page class seems a good idea.

榕城若虚 2024-11-15 00:45:36

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

Add trace=true to the page directive.

人间不值得 2024-11-15 00:45:36

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

Set a boolean field in the PreRender event handler, then check if it was set in the Unload event handler.

睡美人的小仙女 2024-11-15 00:45:36

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

Create a custom event that fires in the PreRender event.

同展鸳鸯锦 2024-11-15 00:45:36

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

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

private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)

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

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

I don't think there is any sort of state stored because the ASP.NET engine does not really need that, as it knows its state implicitely.

Searching with .NET Reflector, it seems the page render events are raised from this internal System.Web.UI.Page method:

private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)

You can have a look at it, there is no notion of state. The only information you can get is the trace. If you have access to the Unload event, then you should have access to the trace? or I miss something :-)

Since the trace is in fact a dataset undercovers (see my answer here: Logging the data in Trace.axd to a text/xml file), you maybe could get the information. But
setting trace=true is not recommended in production though...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文