{Asp.NET页面中事件加载的先后顺序详解}
ASP.NET页面生命周期是理解页面处理流程、优化性能与调试代码的核心基础,掌握各事件的触发顺序与功能,能精准控制代码执行时机,避免资源浪费或逻辑错误,本文系统解析ASP.NET页面中事件的加载顺序,结合实际开发经验,深入分析每个事件的作用,并通过案例展示优化策略,最后通过权威文献佐证内容的可靠性。
页面生命周期阶段与事件
ASP.NET页面从请求到达服务器开始,历经 初始化、加载、回发处理、渲染、卸载 五大阶段,每个阶段触发特定事件,理解这些阶段有助于合理规划代码位置,确保业务逻辑正确执行。
生命周期主要阶段及对应事件:
事件加载先后顺序详解
页面生命周期中,事件的触发顺序严格遵循以下逻辑,从最早期到最终卸载,每个事件的功能和触发时机各不相同:
PreInit事件
Init事件
InitComplete事件
PreLoad事件
Load事件
LoadComplete事件
PreRender事件
SaveStateComplete事件
Render事件
Unload事件
事件顺序小编总结表
为清晰展示各事件顺序与功能,以下是事件顺序小编总结表:
| 事件名称 | 触发时机 | 功能说明 |
|---|---|---|
| 初始化阶段,控件树前 | 判断是否重新编译,动态设置页面属性(如主题、母版页) | |
| 控件树构建后,事件绑定前 | 初始化控件属性,绑定控件事件(如按钮点击事件) | |
| InitComplete | 所有控件初始化完成 | 确认初始化完成,执行后续初始化操作 |
| 加载后,回发时事件绑定前 | 回发场景中加载历史数据,调整控件状态 | |
| 控件状态加载完成,事件绑定后 | 页面核心处理,加载控件数据、执行业务逻辑(代码主要执行位置) | |
| LoadComplete | 所有控件加载完成,数据绑定后 | 确认加载完成,执行样式调整等操作 |
| 即将渲染前 | 最后调整控件属性,修改HTML输出(如设置标题、可见性) | |
| SaveStateComplete | 状态保存后,渲染前 | 确认状态保存完成,清理临时数据 |
| 生成HTML输出 | 自定义HTML输出,添加特殊标记或样式 | |
| 页面卸载前 | 释放资源,关闭数据库连接、清理内存等 |
经验案例: 酷番云 云产品优化页面事件处理
某电商企业用户反映,使用酷番云CDN加速后,页面加载时间仍超过3秒,经分析发现,页面事件处理中事件执行了过多数据库查询,导致耗时,通过调整事件处理顺序,优化如下:
常见问题解答(FAQs)
权威文献与参考资料
读者可全面理解ASP.NET页面事件的加载顺序,掌握各事件的功能与适用场景,结合实际案例优化代码,提升页面性能和用户体验,对于开发人员而言,合理规划事件处理顺序是高效开发ASP.NET应用的关键。
如何使用WebSocket
引擎支持最新的WebSocket Version 13。 在C++中使用详细代码可参考引擎目录下的/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/文件。 头文件中的准备工作首先需要include WebSocket的头文件。 #include network/2d::network::WebSocket::Delegate定义了使用WebScocket需要监听的回调通知接口。 使用WebSocket的类,需要public继承这个Delegate。 class WebSocketTestLayer : public cocos2d::Layer, public cocos2d::network::WebSocket::Delegate并Override下面的4个接口:virtual void onOpen(cocos2d::network::WebSocket* ws);virtual void onMessage(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::Data& data);virtual void onClose(cocos2d::network::WebSocket* ws);virtual void onError(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::ErrorCode& error);后面我们再详细介绍每个回调接口的含义。 新建WebSocket并初始化 提供了一个专门用来测试WebSocket的服务器ws://。 测试代码以链接这个服务器为例,展示如何在Cocos2d-x中使用WebSocket。 新建一个WebSocket:cocos2d::network::WebSocket* _wsiSendText = new network::WebSocket();init第一个参数是delegate,设置为this,第二个参数是服务器地址。 URL中的ws://标识是WebSocket协议,加密的WebSocket为wss://._wsiSendText->init(*this, ws://)WebSocket消息监听在调用send发送消息之前,先来看下4个消息回调。 onOpeninit会触发WebSocket链接服务器,如果成功,WebSocket就会调用onOpen,告诉调用者,客户端到服务器的通讯链路已经成功建立,可以收发消息了。 void WebSocketTestLayer::onOpen(network::WebSocket* ws){if (ws == _wsiSendText){_sendTextStatus->setString(Send Text WS was opened.);}}onMessagenetwork::WebSocket::Data对象存储客户端接收到的数据, isBinary属性用来判断数据是二进制还是文本,len说明数据长度,bytes指向数据。 void WebSocketTestLayer::onMessage(network::WebSocket* ws, const network::WebSocket::Data& data){if (!){_sendTextTimes++;char times[100] = {0};sprintf(times, %d, _sendTextTimes);std::string textStr = std::string(response text msg: )++, +times;log(%s, textStr.c_str());_sendTextStatus->setString(textStr.c_str());}}onClose不管是服务器主动还是被动关闭了WebSocket,客户端将收到这个请求后,需要释放WebSocket内存,并养成良好的习惯:置空指针。 void WebSocketTestLayer::onClose(network::WebSocket* ws){if (ws == _wsiSendText){_wsiSendText = NULL;}CC_SAFE_DELETE(ws);}onError客户端发送的请求,如果发生错误,就会收到onError消息,游戏针对不同的错误码,做出相应的处理。 void WebSocketTestLayer::onError(network::WebSocket* ws, const network::WebSocket::ErrorCode& error){log(Error was fired, error code: %d, error);if (ws == _wsiSendText){char buf[100] = {0};sprintf(buf, an error was fired, code: %d, error);_sendTextStatus->setString(buf);}}send消息到服务器在init之后,我们就可以调用send接口,往服务器发送数据请求。 send有文本和二进制两中模式。 发送文本_wsiSendText->send(Hello WebSocket, Im a text message.);发送二进制数据(多了一个len参数)_wsiSendBinary->send((unsigned char*)buf, sizeof(buf));主动关闭WebSocket这是让整个流程变得完整的关键步骤, 当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接。 close会触发onClose消息,而后onClose里面,我们释放内存。 _wsiSendText->close();在Lua中使用详细代码可参考引擎目录下的/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/文件。 创建WebSocket对象脚本接口相对C++要简单很多,没有头文件,创建WebSocket对象使用下面的一行代码搞定。 参数是服务器地址。 wsSendText = WebSocket:create(ws://)定义并注册消息回调函数回调函数是普通的Lua function,4个消息回调和c++的用途一致,参考上面的说明。 local function wsSendTextOpen(strData)sendTextStatus:setString(Send Text WS was opened.)endlocal function wsSendTextMessage(strData)receiveTextTimes= receiveTextTimes + 1local strInfo= response text msg: .., :setString(strInfo)endlocal function wsSendTextClose(strData)print(_wsiSendText websocket instance closed.)sendTextStatus = nilwsSendText = nilendlocal function wsSendTextError(strData)print(sendText Error was fired)endLua的消息注册不同于C++的继承 & Override,有单独的接口registerScriptHandler。 registerScriptHandler第一个参数是回调函数名,第二个参数是回调类型。 每一个WebSocket实例都需要绑定一次。 if nil ~= wsSendText thenwsSendText:registerScriptHandler(wsSendTextOpen,_OPEN)wsSendText:registerScriptHandler(wsSendTextMessage,_MESSAGE)wsSendText:registerScriptHandler(wsSendTextClose,_CLOSE)wsSendText:registerScriptHandler(wsSendTextError,_ERROR)endsend消息Lua中发送不区分文本或二进制模式,均使用下面的接口。 wsSendText:sendString(Hello WebSocket中文, Im a text message.)主动关闭WebSocket当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接,以释放服务器和客户端的资源。 close会触发_CLOSE消息。 wsSendText:close()在JSB中使用详细代码可参考引擎目录下的/samples/Javascript/Shared/tests/ExtensionsTest/NetworkTest/文件。 创建WebSocket对象脚本接口相对C++要简单很多,没有头文件,创建WebSocket对象使用下面的一行代码搞定。 参数是服务器地址。 this._wsiSendText = new WebSocket(ws://);设置消息回调函数JSB中的回调函数是WebSocket实例的属性,使用匿名函数直接赋值给对应属性。 可以看出JS语言的特性,让绑定回调函数更加优美。 四个回调的含义,参考上面c++的描述。 this._ = function(evt) {self._(Send Text WS was opened.);};this._ = function(evt) {self._sendTextTimes++;var textStr = response text msg: ++, +self._sendTextTimes;(textStr);self._(textStr);};this._ = function(evt) {(sendText Error was fired);};this._ = function(evt) {(_wsiSendText websocket instance closed.);self._wsiSendText = null;};send消息发送文本,无需转换,代码如下:this._(Hello WebSocket中文, Im a text message.);发送二进制,测试代码中,使用_stringConvertToArray函数来转换string为二进制数据,模拟二进制的发送。 new Uint16Array创建一个16位无符号整数值的类型化数组,内容将初始化为0。 然后,循环读取字符串的每一个字符的Unicode编码,并存入Uint16Array,最终得到一个二进制对象。 _stringConvertToArray:function (strData) {if (!strData)returnnull;var arrData = new Uint16Array();for (var i = 0; i < ; i++) {arrData[i] = (i);}return arrData;},send二进制接口和send文本没有区别,区别在于传入的对象,JS内部自己知道对象是文本还是二进制数据,然后做不同的处理。 var buf = Hello WebSocket中文,\0 Im\0 a\0 binary\0 message\0.;var binary = this._stringConvertToArray(buf);this._();主动关闭WebSocket当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接,以释放服务器和客户端的资源。 close会触发onclose消息。 onExit: function() {if (this._wsiSendText)this._();}
servlet容器在启动web应用时创建哪些对象
Servlet容器 —— 以tomcat为例在tomcat容器等级中,context容器直接管理servlet在容器中的包装类Wrapper,所以Context容器如何运行将直接影响servlet的工作方式。 tomcat容器模型如下:一个context对应一个web工程,在tomcat的配置文件中,可以发现context的配置(在eclipse工程中,可在部署路径的conf文件夹zhoing找到)[html] view plaincopy在CODE上查看代码片派生到我的代码片Context docBase=/Users/wongrobin/all/projects/tech-test/java-test////tmp0/wtpwebapps/base-webapp path=/base-webapp reloadable=true source=:base-webapp/>Servlet容器的启动过程——以tomcat为例Tomcat7增加了一个启动类:[html] view plaincopy在CODE上查看代码片派生到我的代码片创建一个Tomcat的一个实例对象并调用start方法就可以启动tomcat。 还可以通过这个对象来增加和修改tomcat的配置参数,如可以动态增加context,servlet等。 在tomcat7中提供的example中,看是如何添加到context容器中:[java] view plaincopy在CODE上查看代码片派生到我的代码片Tomcat tomcat = getTomcatInstance();File appDir = new File(getBuildDirectory(), webapps/examples);(null, /examples, ());();ByteChunk res = getUrl(+ getPort() + /examples/servlets/servlet/HelloWorldExample);asserttrue(()(
Hello World!
) > 0);这段代码创建了一个Tomcat实例并新增了一个WEB应用,然后启动Tomcat并调用其中的一个HelloWorldExampleServlet。 Tomcat的addWebap方法的代码如下:[java] view plaincopy在CODE上查看代码片派生到我的代码片public Context addWebapp(Host host, String url, String path) {silence(url);Context ctx = new StandardContext();( url );(path);if (defaultRealm == null) {initSimpleAuth();}(defaultRealm);(new DefaultWebXmlListener());ContextConfig ctxCfg = new ContextConfig();(ctxCfg);(org/apache/catalin/startup/NO_DEFAULT_XML);if (host == null) {getHost()(ctx);} else {(ctx);}return ctx;}一个WEB应用对应一个context容器,也就是servlet运行时的servlet容器。 添加一个web应用时将会创建一个StandardContext容器,并且给这个context容器设置必要的参数,url和path分别代表这个应用在tomcat中的访问路径和这个应用实际的物理路径,这两个参数与tomcat配置中的两个参数是一致的。 其中一个最重要的一个配置是ContextConfig,这个类会负责整个web应用配置的解析工作。 最后将这个context容器加入到父容器host中。 接下来会调用tomcat的start方法启动tomcat。 Tomcat的启动逻辑是基于观察者模式的,所有的容器都会继承Lifecycle接口,它管理着容器的整个生命周期,所有容器的修改和状态改变都会由它通知已经注册的观察者。 Tomcat启动的时序如下:当context容器初始状态设置Init时,添加到context容器的listener将会被调用。 ContextConfig继承了LifecycleListener接口,它是在调用时被加入到StandardContext容器中的。 ContextConfig类会负责整个WEB应用的配置文件的解析工作。 ContextConfig的init方法将会主要完成一下工作:创建用于解析XML配置文件的contextDigester对象读取默认的文件,如果存在则解析它读取默认的Host配置文件,如果存在则解析它读取默认的Context自身的配置文件,如果存在则解析它设置Context的DocBaseContextConfig的init方法完成后,Context容器会执行startInternal方法,这个方法包括如下几个部分:创建读取资源文件的对象创建ClassLoader对象设置应用的工作目录启动相关的辅助类,如logger,realm,resources等修改启动状态,通知感兴趣的观察者子容器的初始化获取ServletContext并设置必要的参数初始化“load on startuo”的ServletWeb应用的初始化工作——以tomcat为例WEB应用的初始化工作是在ContextConfig的configureStart方法中实现的,应用的初始化工作主要是解析文件,这个文件是一个WEB应用的入口。 Tomcat首先会找globalWebXml,这个文件的搜索路径是engine的工作目录下的org/apache/catalina/startup/NO-DEFAULT_XML或conf/。 接着会找hostWebXml,这个文件可能会在()/conf/${EngineName}/${HostName}/中。 接着寻找应用的配置文件examples/WEB-INF/,文件中的各个配置项将会被解析成相应的属性保存在WebXml对象中。 接下来会讲WebXml对象中的属性设置到context容器中,这里包括创建servlet对象,filter,listerner等,这些在WebXml的configureContext方法中。 下面是解析servlet的代码对象:[java] view plaincopy在CODE上查看代码片派生到我的代码片for (ServletDef servlet : ()) {Wrapper wrapper = ();String jspFile = ();if (jspFile != null) {(jspFile);}if (() != null) {(()());}if (() != null) {(()());}(());Map怎么进行端口映射?
2.2要装个ipmasqadm #先用ipchains把发到你的外部ip的报文作标记1ipchains -A input -d 你的外部ip [端口] -m 1 #标记1的报文转发到你的内部ip上ipmasqadm mfw -A -m 1 -r 你的内部ip [端口] #最后ipchains -A forward -s 你的内部ip [端口] -j MASQ man一下ipmasqadm 就知道了,ipchains和iptables差异很














发表评论