ASP.Net请求处理机制初步探索之旅 - Part 4 WebForm页面生命周期

开篇:上一篇我们了解了所谓的请求处理管道,在众多的事件中微软开放了19个重要的事件给我们,我们可以注入一些自定义的业务逻辑实现应用的个性化设计。本篇,我们来看看WebForm模式下的页面生命周期。

(1)Part 1:前奏

(2)Part 2:核心

(3)Part 3:管道

(4)Part 4:WebForm页面生命周期

(5)Part 5:MVC页面声命周期

一、ASP.Net Page的两个重要部分

  在前面对于请求处理管道的介绍中,我们已经了解了一个ASP.NET WebForm页面请求事件的整体流程。那么,在其中一个最重要的部分就是ASP.NET Page页面,但是我们并没有对其进行详细讨论。因此,我们在此深入地了解一下ASP.NET页面事件。

  每一个ASP.NET Page页都有2个部分:一个部分是在浏览器中进行显示的部分,它包含了HTML标签、viewstate形式的隐藏域 以及 在HTML input中的数据。当这个页面被提交到服务器时,这些HTML标签会被创建到ASP.NET控件,并且viewstate还会和表单数据绑定在一起。另一个部分是在xxx.cs文件中的进行业务逻辑操作的部分,一旦你在后置代码中得到所有的服务器控件,你可以执行和写入你自己的逻辑并呈现给客户浏览器。

  其中,后台代码类是前台页面类的父类,前台页面类则是后台代码类的子类。这一点,可以通过查看每个aspx文件中的头部,我们都会看到以下的一句代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="FirstPage.aspx.cs" Inherits="WebFormDemo.FirstPage" %>

  其中CodeBehind这个属性定义了此aspx页面的专属后台代码文件的名称,而Inherits这个属性则定义了此aspx页面所要继承的父类的名称(这也可以简单地说明,aspx页面会单独生成一个类,与后台代码类不重合在一起)。因此,aspx.cs就是aspx的后置处理代码,负责处理aspx中<%%>和runat="server"的内容。

  现在这些HTML控件会作为ASP.NET控件存活在服务器上,ASP.NET会触发一系列的事件,我们也可以在这些事件中注入自定义逻辑代码。根据你想要执行什么样的任务/逻辑,我们需要将逻辑合理地放入这些事件之中。

TIP:大部分的开发者直接使用Page_Load来干所有的事情,但这并不是一个好的思路。因此,无论是填充控件、设置ViewState还是应用主题等所有发生在页面加载中的所有事情。因此,如果我们能够在合适的事件中放入逻辑,那么毫无疑问我们代码将会干净很多。

二、ASP.Net Page的页面事件流程

顺序事件名称控件初始化ViewState可用表单数据可用什么逻辑可以写在这里?
1InitNoNoNo注意:你可以通过使用ASP.NET请求对象访问表单数据等,但不是通过服务器控件。
动态地创建控件,如果你一定要在运行时创建;任何初始化设置;母版页及其设置。在这部分中我们没有获得viewstate、提交的数据值及已经初始化的控件。
2Load View StateNot guaranteedYesNot guaranteed你可以访问View State及任何同步逻辑,你希望viewstate被推到后台代码变量可以在这里完成。
3PostBackdataNot guaranteedYesYes你可以访问表单数据。任何逻辑,你希望表单数据被推到后台代码变量可以在这里完成。
4LoadYesYesYes在这里你可以放入任何你想操作控件的逻辑,如从数据库填充combox、对grid中的数据排序等。这个事件,我们可以访问所有控件、viewstate、他们发送过来的值。
5ValidateYesYesYes如果你的页面有验证器或者你想为你的页面执行验证,那就在这里做吧。
6EventYesYesYes

如果这是通过点击按钮或下拉列表的改变的一个回发,相关的事件将被触发。与事件相关的任何逻辑都可以在这里执行。

PS:这个事件想必很多使用WebForm的开发人员都很常用吧,是否记得那些Button1_Click(Object sender,EventArgs e)?

7Pre-renderYesYesYes如果你想对UI对象做最终的修改,如改变属性结构或属性值,在这些控件保存到ViewState之前。
8Save ViewStateYesYesYes一旦对服务器控件的所有修改完成,将会保存控件数据到View State中。
9RenderYesYesYes如果你想添加一些自定义HTML到输出,可以在这里完成。
10UnloadYesYesYes任何你想做的清理工作都可以在这里执行。

三、反编译探秘ASP.Net Page页面生命周期

  前面我们简单地了解了一下ASP.NET Page的页面事件,现在我们来通过Reflector反编译一下一个demo程序集,来感受一下ASP.NET Page的页面生命周期。

3.1 准备一个ASP.NET项目

  (1)假如我们有以下的名为Index的一个aspx页面:

复制代码

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="headIndex" runat="server"><title>Index页</title>
</head>
<body><form id="formIndex" runat="server"><div>哈哈,我是ASP.Net WebForm,下面看我的表演。<br /><%for (int i = 0; i < 5; i++){Response.Write("I am a webform page.<br/>");}%><br /><%= GetServerTime() %><br /><asp:TextBox ID="txtDateTime" runat="server"></asp:TextBox><asp:Button ID="btnGetTime"runat="server" Text="获取时间" οnclick="btnGetTime_Click" /><br /><% GetDllInfo(); %></div></form>
</body>
</html>

复制代码

  (2)Index所对应的后台代码如下:

复制代码

namespace PageLifeCycleDemo
{public partial class Index : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){}protected string GetServerTime(){string result = "服务器时间:" + DateTime.Now.ToString();return result;}protected void GetDllInfo(){Response.Write("页面类名称:" + this.GetType() + "<br/>");Response.Write("程序集地址:" + this.GetType().Assembly.Location + "<br/>");Response.Write("父类的名称:" + this.GetType().BaseType + "<br/>");Response.Write("程序集地址:" + this.GetType().BaseType.Assembly.Location + "<br/>");}protected void btnGetTime_Click(object sender, EventArgs e){txtDateTime.Text = DateTime.Now.ToString();}}
}

复制代码

  这里,我们来重点关注一下这个方法:我们可以通过写入以下代码,然后在aspx中<% GetDllInfo(); %>调用,它显示了我们这个ASP.NET项目所属的程序集在哪个位置?

复制代码

protected void GetDllInfo()
{Response.Write("页面类名称:"+this.GetType() + "<br/>");Response.Write("程序集地址:"+this.GetType().Assembly.Location + "<br/>");Response.Write("父类的名称:"+this.GetType().BaseType + "<br/>");Response.Write("程序集地址:"+this.GetType().BaseType.Assembly.Location + "<br/>");
}

复制代码

  浏览页面,会显示以下结果:通过下图可以看到,我们的Index这个页面会生成一个ASP.index_aspx的类,其父类是Index。

3.2 反编译生成的临时程序集

  ①将DLL拖到Reflector中进行查看源代码

  通过上面显示的路径找到dll,并拖到反编译工具(ILSpy或者Reflector,前者开源免费,后者已经收费,但天朝,你懂的。)进行查看。通过下图可以看出,页面类aspx是后台代码类所绑定的子类,它的名称是aspx文件名加上“_aspx”后缀。因此,这里也就解释了为什么在aspx中要访问的方法必须是public和protected的访问修饰符才可以。

  ②一个大型Control:Page类

  从上面可以看出,页面类继承自后置代码类,而后置代码类又继承自Page类。我们从上一篇管道可以知道,在请求处理管道的第8个事件中创建了Page类对象,那么我们去看看Page类。

  Page类继承自TemplateControl,顾名思义,Page类是否就是一个模板控件呢?再看看TemplateControl类:

  果不其然,其父类是Control类,Page就是一个封装过的大控件!那么,我们在Page中拖的那些runat="server"的服务器控件,又是保存在哪里的呢?

  原来,在Control父类中,有一个Controls的属性,它是一个控件的集合:Page中的所有控件,都会存在于这个集合中。

  ③页面生命周期的入口:Page类的ProcessRequest方法

  从上一篇请求处理管道中,我们知道在第11和第12个事件之间会调用Page类对象的ProcessRequest方法进入页面生命周期。那么我们来看看这个ProcessRequest方法:

  从图中可以看出,这个方法中首先通过调用页面类对象(我们请求的页面都是继承于Page类的)重写的FrameworkInitialize方法开始我们经常听到的构造控件树的过程。下面我们转到index_aspx这个页面类重写的FrameworkInitialize方法中取看看是否是进行了构造页面控件树的操作:

  

  ④BuildControlTree:构造页面控件树

  看到这里,我们不由地想问,什么是页面控件树?在一个aspx页面中,runat="server"的控件集合构成了如下图所示的一棵页面控件树,他们被一一实例化,并依据层级关系存储到了controls集合中。

  了解了什么是页面控件树,现在我们看看是如何来构造这棵树的,通过查看BuildControlTree方法,发现它调用了多个名为BuildControlX的方法,依次实例化我们页面中所需的控件,并添加到控件集合中(这里其实是将这些服务器控件作为子控件添加到页面(页面本身就是一个大的控件)中,在树形结构中Page就是一个根节点,而那些Page中的控件则是Page的孩子节点)。

  那么,这些BuildControlX(X代表数字)方法又在做些什么事呢?我们可以通过查看一个BuildControl方法,看看如何打造HtmlForm的:

  可以看出,在构造HtmlForm控件的过程中,不仅为其设置了ID(_ctrl.ID="formIndex"),还为其指定了渲染方法(通过设置委托_ctrl.SetRenderMethodDelegate())。又因为我们拖了一个TextBox和Button在其中,于是在实例化HtmlForm这个控件的途中,又去实例化TextBox和Button对象,并将其作为HtmlForm的子节点,形成一个层级关系。

  ⑤确定IsPostBack:是否第一次请求该页面

  现在重新回到Page类的ProcessRequest方法中,在创建页面控件树完成之后,开始进入一个ProcessRequestMain方法,这个方法则真正地开启了页面生命周期之门。

复制代码

private void ProcessRequest(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)
{......                     this.ProcessRequestMain(includeStagesBeforeAsyncPoint, includeStagesAfterAsyncPoint);......
}

复制代码

  我们经常在Page_Load方法中使用Page.IsPostBack属性来判断请求是否是回发,那么它是在哪里设置的呢?原来,在ProcessRequestMain方法中:

  ⑥初始化操作:PreInit-->Init-->InitComplete

  接下来就是初始化操作了,初始化操作分为了三个阶段:预初始化、初始化(使用递归方式)、初始化完成。

复制代码

    private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint){......this.PerformPreInit();......this.InitRecursive();......this.OnInitComplete();......}

复制代码

  预初始化主要利用App_Themes目录中的内容进行初始化主题,并应用模板页。

  这里我们主要看看初始化操作,通过查看源代码,可以看出,该方法通过递归调用子控件的初始化方法,完成了控件集合中所有控件的初始化操作。

复制代码

    internal virtual void InitRecursive(Control namingContainer){......int count = this._controls.Count;for (int i = 0; i < count; i++){Control control = this._controls[i];control.UpdateNamingContainer(namingContainer);if (((control._id == null) && (namingContainer != null)) && !control.flags[0x40]){control.GenerateAutomaticID();}control._page = this.Page;control.InitRecursive(namingContainer);}......}

复制代码

   再看看初始化方法中都做了哪些初始化操作,细细一看,原来就是为其动态地生成一个ID(control.GenerateAutomaticID()),然后将该控件的page指针指向当前Page页等。PreLoad 预加载在 Load 事件之前对页或控件执行处理,

  ⑦加载操作:(LoadState-->ProcessPostData-->)PreLoad-->Load-->

(ProcessPostData-->RaiseChangedEvents-->RaisePostBackEvent-->)LoadComplete  

  • 首先看看(LoadState-->ProcessPostData)

  初始化完成之后,ASP.NET会通过IsPostBack判断是否是第一次请求,如果不是,那么首先会加载ViewState并对回发的数据进行处理。

复制代码

        private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint){if(this.IsPostBack){......this.LoadAllState();......this.ProcessPostData(this._requestValueCollection, true);......}}

复制代码

  至于ViewState是什么?又不了解的朋友,可以浏览我的另一篇博文:ASP.NET WebForm温故知新:ViewState,这里就不再赘述。这里LoadAllState方法主要是将隐藏域中的_VIEWSTATE通过解码获取控件的状态与数据信息,而ProcessPostData方法则是进行了两个部分的操作:一是将刚刚获取到的各个控件的状态与数据信息填充到页面控件树中所对应的各个控件中去,二是对比控件状态是否发生了改变?比如被点击了?被触发了某个事件(例如TextChanged、SelectedIndexChanged等)?如有触发事件,则把需要触发事件的控件放到一个集合当中去。

  • 再来看看PreLoad-->Load

  处理完ViewState后,就开始进行正式地加载操作了,如下代码所示:

复制代码

        private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint){......this.OnPreLoad(EventArgs.Empty);......this.LoadRecursive();......}

复制代码

  在正式加载过程中也分为了两个部分,一个是PreLoad预加载,另外一个则是重头戏Load加载(通过方法名可以推断,该方法是通过递归方式调用加载的)。首先,调用了OnPreLoad方法进行预加载操作,如果我们需要在 Load 事件之前对页或控件(这时页面控件树已经构造完成)执行处理,就可以使用该事件。通过查看源代码,在PreLoad方法中会遍历一个PreLoad事件集合(我们可以自定义注入我们想要的事件),然后依次执行委托所持有的事件。

复制代码

protected virtual void OnPreLoad(EventArgs e)
{EventHandler handler = (EventHandler) base.Events[EventPreLoad];if (handler != null){handler(this, e);}
}

复制代码

  PreLoad之后就是重头戏,也是我们最为熟悉的Load了,在调用LoadRecursive()方法进入Load事件。

复制代码

internal virtual void LoadRecursive()
{if (this._controlState < ControlState.Loaded){if (this.AdapterInternal != null){this.AdapterInternal.OnLoad(EventArgs.Empty);}else{this.OnLoad(EventArgs.Empty);}}if (this._controls != null){string errorMsg = this._controls.SetCollectionReadOnly("Parent_collections_readonly");int count = this._controls.Count;for (int i = 0; i < count; i++){this._controls[i].LoadRecursive();}this._controls.SetCollectionReadOnly(errorMsg);}if (this._controlState < ControlState.Loaded){this._controlState = ControlState.Loaded;}
}

复制代码

  从上面可以看出:ASP.NET页面首先调用自身的OnLoad方法以引发自身的Load事件,接着递归调用 Contorls 集合中各个控件的OnLoad方法以引发它们的Load事件。那么,我们在页面后置代码类中经常使用的Page_Load事件方法是在哪里调用的呢?相信我们都有了答案,就在页面自身的OnLoad方法中。

  • 二次经历(ProcessPostData)

复制代码

        private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint){if(this.IsPostBack){......this.ProcessPostData(this._leftoverPostData, false);......this.RaiseChangedEvents();......this.RaisePostBackEvent(this._requestValueCollection);......}}

复制代码

  加载结束后,会经历第二次的处理回发数据的事件。那么,我们不禁会问,为何还要第二次进行ProcessPostData方法的调用,我们刚刚不是都已经对ViewState进行了解码并对应到了对应控件树中的控件了嘛?这里,我们首先看看下面一段代码:

复制代码

        protected void Page_Load(object sender, EventArgs e){if (IsPostBack){TextBox txtTest = new TextBox();txtTest.Text = "动态创建的TextBox";formIndex.Controls.Add(txtTest);}}

复制代码

  假如我们要在Page_Load事件中动态地为Form添加一个TextBox控件,那么之前的页面控件树就发生了改变,所以,这里需要进行第二次的ProcessPostData方法,现在豁然开朗了吧。

  • 事件触发(RaiseChangedEvents-->RaisePostBackEvent)

  在第二次处理回发数据之后,会调用RaiseChangedEvents方法触发控件状态改变事件响应方法,例如TextBox_TextChanged、DropDownList_SelectedIndexChanged事件(这些事件中不包括Button_Click这种回发事件)等。查看源代码,通过遍历状态改变了的控件的集合(在第一次进行ProcessPostData时会检查控件的状态是否发生了改变,如果改变了就添加到一个集合中)

复制代码

internal void RaiseChangedEvents()
{if (this._changedPostDataConsumers != null){for (int i = 0; i < this._changedPostDataConsumers.Count; i++){Control control = (Control) this._changedPostDataConsumers[i];if (control != null){IPostBackDataHandler postBackDataHandler = control.PostBackDataHandler;if (((control == null) || control.IsDescendentOf(this)) && ((control != null) && (control.PostBackDataHandler != null))){postBackDataHandler.RaisePostDataChangedEvent();}}}}
}

复制代码

  在处理完状态改变事件响应方法后,会调用RaisePostBackEvent方法触发例如按钮控件的回发事件,例如Button_Click回发事件。

复制代码

private void RaisePostBackEvent(NameValueCollection postData)
{if (this._registeredControlThatRequireRaiseEvent != null){this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);}else{string str = postData["__EVENTTARGET"];bool flag = !string.IsNullOrEmpty(str);if (flag || (this.AutoPostBackControl != null)){Control control = null;if (flag){control = this.FindControl(str);}if ((control != null) && (control.PostBackEventHandler != null)){string eventArgument = postData["__EVENTARGUMENT"];this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument);}}else{this.Validate();}}
}

复制代码

  通过查看代码,发现通过回传的表单数据中根据__EVENTTARGET与__EVENTARGUMENT进行事件的触发。我们可以通过查看ASP.NET生成的前端HTML代码看到这两个参数:下图是一个设置为AutoPostBack的DropDownList控件,可以发现回发事件都是通过调用_doPostBack这个js代码进行表单的submit,而表单中最重要的两个参数就是eventTarget和eventArgument。

  通过浏览器提供的开发人员工具查看数据请求报文,可以看到除了提交form中的input外,还提交了ASP.Net WebForm预置的一些隐藏字段,而这些隐藏字段则是WebForm为我们提供便利的基础。比如EventTarget则记录刚刚提交给服务器的是哪个服务器控件。

  事件触发完成之后,加载操作就完成了,这时会调用OnLoadComplete方法进行相关的事件,这里就不再赘述了。

  • 页面渲染 PreRender-->PreRenderComplete-->SaveState-->SaveStateComplete-->Render

  这一阶段就进入了页面生命周期的尾巴,开始最终页面的渲染流程:

复制代码

        private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint){......this.PreRenderRecursiveInternal();......this.PerformPreRenderComplete();......this.SaveAllState();......this.OnSaveStateComplete(EventArgs.Empty);......this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));......}

复制代码

  这里我们主要看看PreRenderSaveStateRender三个事件。

  既然已经进入了页面渲染阶段,为何还要有一个PreRender预呈现阶段?通过查找资料,我们发现微软这么设计是为了给开发者提供一个最后一次更改页面控件状态或数据的机会,也就说:你可以再在这里注入一个逻辑,最后一次改变控件值,或者统一地改变控件状态为某个指定状态。

  然后就是SaveState,这个很好理解,也就说:刚刚给了你最后一次更改的机会结束后,我就要保存最终的ViewState了。这里需要注意的是:服务器在向浏览器返回html之前,对ViewState中的内容是进行了Base64编码的;

  最后就是Render,进行最终的页面呈现了,换句话说:就是拼接形成HTML字符串。在这个阶段,Page 对象会遍历页面控件树并在每个控件上递归地调用此方法。所有 ASP.NET Web 服务器控件都有一个用于写出发送给浏览器的控件标记的 Render 方法。通过对源代码进行追踪,可以看到以下代码:

复制代码

internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
{if ((this.RareFields != null) && (this.RareFields.RenderMethod != null)){writer.BeginRender();this.RareFields.RenderMethod(writer, this);writer.EndRender();}else if (children != null){foreach (Control control in children){control.RenderControl(writer);}}
}

复制代码

  在Render过程中,会判断当前控件是否含有子控件集合,如果有,那么遍历各个子控件的Render方法进行HTML的渲染。可以想象,从页面控件树的根节点调用Render方法,会依次递归调用其所有子节点的Render方法,从而得到一个完整的HTML代码。

  那么,Render方法结束后,生成的HTML代码保存到了哪里呢?原来,Render方法的输出会写入Page类对象的 Response 属性的 OutputStream 中,这就是最终的输出流作为响应报文通过HTTP协议返回给浏览器端了。

  • 页面卸载 Unload

  自此,狭义上的页面生命周期就结束了,但广义上的页面声明周期事件还未结束,还会经历一个UnLoad事件,该事件首先针对每个控件发生,继而针对该页发生。在控件中,使用该事件对特定控件执行最后清理,如关闭控件特定数据库连接。对于页自身,使用该事件来执行最后清理工作,如:关闭打开的文件和数据库连接,或完成日志记录或其他请求特定任务。总而言之,Unload就是进行最后的清理工作,释放资源。

总体概览

  一篇文章下来,已耗费了好多时间,如果你觉得对你有用,那就麻烦点个推荐吧。如果你觉得本文很烂,那点个反对也是可以的。后面Part 5会探秘ASP.NET MVC的页面生命流程,今天就此停笔,谢谢!

参考资料

(1)农村出来的大学生,《ASP.NET网页请求处理全过程(反编译)》:http://www.cnblogs.com/poorpan/archive/2011/09/25/2190308.html

(2)我自己,《【翻译】ASP.NET应用程序和页面声明周期》:http://www.cnblogs.com/edisonchou/p/3958305.html

(3)Shivprasad koirala,《ASP.NET Application and Page Life Cycle》:http://www.codeproject.com/Articles/73728/ASP-NET-Application-and-Page-Life-Cycle

(4)碧血轩,《ASP.NET页面生命周期》:http://www.cnblogs.com/xhwy/archive/2012/05/20/2510178.html

(5)木宛城主,《ASP.NET那点不为人知的事儿》:http://www.cnblogs.com/OceanEyes/archive/2012/08/13/aspnetEssential-1.html

(6)千年老妖,《ASP.NET页面生命周期》:http://www.cnblogs.com/hanwenhuazuibang/archive/2013/04/07/3003289.html

(7)MSDN,《Page事件》:http://msdn.microsoft.com/zh-cn/library/system.web.ui.page_events(v=vs.80).aspx

偶像的歌

 PS:背景音乐 from 张国荣 电影英雄本色中的插曲 《当年情

 

 

作者:周旭龙

出处:http://edisonchou.cnblogs.com/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

REVERSE-COMPETITION-GeekChallenge2021

REVERSE-COMPETITION-GeekChallenge2021Re0刘壮桌面美化大师买ActivityRe1调试珍惜生命new_languageeasypycBrute_forcewin32wasm猜拳have_a_teaRe0 64位exe&#xff0c;ida打开&#xff0c;main函数中没发现什么重要的逻辑 ShiftF12打开字符串窗口&#xff0c;直接找到flag明…

ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

开篇&#xff1a;上一篇我们了解了在WebForm模式下一个Page页面的生命周期&#xff0c;它经历了初始化Init、加载Load以及呈现Render三个重要阶段&#xff0c;其中构造了页面控件树&#xff0c;并对页面控件树进行了大量的递归操作&#xff0c;最后将与模板结合生成的HTML返回给…

REVERSE-PRACTICE-CTFSHOW-6

REVERSE-PRACTICE-CTFSHOW-6真的是签到批量生产的伪劣产品来一个派森snake真的是签到 附件是一个压缩包&#xff0c;解压需要密码&#xff0c;但是题目没有给到解压密码 实际上是压缩包伪加密&#xff0c;将如图橙色处原本的字节0x09改为0x00&#xff0c;保存后即可解压出文件…

REVERSE-PRACTICE-CTFSHOW-7

REVERSE-PRACTICE-CTFSHOW-7签层饼Tea_tube_poteasy贪吃蛇的秘密签层饼 32位exe&#xff0c;ida打开 main函数中&#xff0c;输入两个大于0的数字&#xff0c;如果flag_num为0&#xff0c;则将两个输入作为flag的一部分&#xff0c;打印flag 选中input_1按x查找交叉引用&…

HttpModule与HttpHandler详解(转)

ASP.NET对请求处理的过程&#xff1a; 当请求一个*.aspx文件的时候&#xff0c;这个请求会被inetinfo.exe进程截获&#xff0c;它判断文件的后缀&#xff08;aspx&#xff09;之后&#xff0c;将这个请求转交给 ASPNET_ISAPI.dll&#xff0c;ASPNET_ISAPI.dll会通过http管道&am…

Windows 系统中 Python下 Pygame 的安装

Pygame是跨平台Python模块&#xff0c;专为电子游戏设计&#xff0c;可用于管理图形、动画乃至声音&#xff0c;建立在SDL基础上&#xff0c;允许实时电子游戏研发而无需被低级语言&#xff08;如机器语言和汇编语言&#xff09;束缚&#xff0c;通过使用Pygame来处理在屏幕上绘…

REVERSE-PRACTICE-CTFSHOW-8

REVERSE-PRACTICE-CTFSHOW-8Matara OkinaanniuwarmupeMatara Okina apk文件&#xff0c;jadx-gui打开 MainActivity什么都没有&#xff0c;来到FlagActivity scheme&#xff0c;host这些看不懂 第44行有个ans和bytes的比较&#xff0c;ans已知&#xff0c;bytes是从某个地方获…

Html控件和Web控件(转)

作为一名ASP.NET的初学者&#xff0c;了解并且区别一些混淆概念是很必须的&#xff0c;今天这篇博文 就是主要向大家介绍一下Html控件和Web控件。在ASP.net中&#xff0c;用户界面控件主要就是 Html控件和Web控件&#xff0c;在前台页面上看&#xff0c;两种控件非常相似&…

VMware Pro 14 安装 Ubuntu 18.04 详细教程

目录● 安装步骤1.下载安装 VMware Workstation Pro 142.下载 Ubuntu 18.04 系统3.在 VMware 中创建虚拟机4.在虚拟机上安装 Ubuntu 系统● 安装过程中可能会出现的一些问题 1.在虚拟机上安装 Ubuntu 系统的过程中卡死不动 2.Ubuntu 不能全屏显示● 安装步骤 1.下载安装 VMware…

Web服务器控件和HTML控件的区别与联系

我们知道&#xff0c;在ASP.NET中&#xff0c;使用了两类控件&#xff0c;一类是HTML控件&#xff0c;还有一类是WEB控件。 WEB控件我们已经很熟悉&#xff0c;因为它是ASP.NET提供&#xff0c;一般关于ASP.NET的教程文章都会仔细介绍这些控件的详细应用技巧&#xff1b; 而H…

Hexo 博客优化之博客美化系列(持续更新)

2022-01-25 更新&#xff1a;博客新地址&#xff1a;https://www.itbob.cn/&#xff0c;文章距上次编辑时间较远&#xff0c;部分内容可能已经过时&#xff01; 本文将讲述一些 Hexo 博客的美化&#xff0c;本文以作者 luuman 的 spfk 主题和作者 xaoxuu 的 Material X 主题为例…

一台电脑部署两个或多个 Hexo 博客(一台电脑使用两个或多个 GitHub 账号)

由于个人原因需要在一台电脑上部署两个Hexo博客&#xff0c;本来以为挺简单&#xff0c;没想到问题重重&#xff0c;首先是一个GitHub账号只能搭建一个Hexo博客&#xff0c;因此就需要使用其他GitHub账号&#xff1b;其次是一台电脑绑定两个GitHub账号&#xff0c;则需要两对公…

element.style内联样式修改

最近在修改我个人博客的一个样式时发现&#xff0c;无论我如何修改style里面的值&#xff0c;页面上的样式都不会被修改&#xff0c;F12检查一下发现个element.style&#xff0c;但是却找不到这个值在哪里&#xff0c;查资料后才知道element.style为内联样式&#xff0c;基本很…

免费CDN:jsDelivr+Github 使用方法

CDN的全称是Content Delivery Network&#xff0c;即内容分发网络。CDN是构建在网络之上的内容分发网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发、调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c;降低网络拥塞&…

EasyUI学习总结(一)——EasyUI入门

一、EasyUI下载 EasyUI官方下载地址&#xff1a;http://www.jeasyui.com/download/index.php&#xff0c;目前最新的版本是&#xff1a;jQuery EasyUI 1.4.1 下载完成之后&#xff0c;得到压缩包&#xff0c;解压后&#xff0c;得到一个【jquery-easyui-1.4.1】文件夹&#xff…

PWN-PRACTICE-CTFSHOW-1

PWN-PRACTICE-CTFSHOW-1PWN签到题pwn02pwn03pwn04PWN签到题 nc连上去就会打印flag pwn02 栈溢出&#xff0c;覆盖返回地址为后门函数stack起始地址即可 # -*- coding:utf-8 -*- from pwn import * #ioprocess("./pwn1") ioremote("pwn.challenge.ctf.show&…

利用QQ邮箱设置个性域名邮箱,并在网易邮箱大师客户端添加域名邮箱

平常我们使用的邮箱都是xxxqq.com、xxx126.com、xxx163.com、xxxgmail.com之类的&#xff0c;这些邮箱会暴露你的QQ号、电话号等信息&#xff0c;最重要的是后缀都和别人一样&#xff0c;没有个性&#xff0c;也许你看见过xxxliruihao.com、xxxwangxiaoxiao.com之类的带有个性后…

MVC和WebForm区别

WebForm的理解 1、 WebForm概念 ASP.NETWebform提供了一个类似于Winform的事件响应GUI模型&#xff08;event-drivenGUI&#xff09;&#xff0c;隐藏了HTTP、HTML、JavaScript等细节&#xff0c;将用户界面构建成一个服务器端的树结构控件&#xff08;Control&#xff09;&a…

VMware Pro 15 安装 Deepin15.9 国产操作系统详细教程

Deepin是由武汉深之度科技有限公司开发的Linux发行版&#xff0c;个人认为其界面设计非常美观&#xff0c;而且作为国产操作系统&#xff0c;值得我们去体验和支持&#xff01; 文章目录1.下载安装 VMware Workstation Pro 152.下载 Deepin15.9 系统3.在 VMware 中创建虚拟机4.…

Asp.Net WebForm生命周期的详解

一&#xff0e;http://Asp.Net页面生命周期的概念 当我们在浏览器地址栏中输入网址&#xff0c;回车查看页面时&#xff0c;这时会向服务器端IIS&#xff09;发送一个request请求&#xff0c;服务器就会判断发送过来的请求页面&#xff0c;当完全识别 TTP页面处理程序类后&…