zoukankan      html  css  js  c++  java
  • 从源码看ASP.NET框架(一)-打造页面控件树

    测试实例如下:

    前台代码MyFirstWeb.aspx(没有服务器控件,即没有runat)

    CodeBehind=”MyFirstWeb.aspx.cs”:表示代码后置类文件
    Inherits=”SimpleWeb.MyfirstWeb”:表示该前台类继承于代码后置类文件中的哪个类
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MyFirstWeb.aspx.cs" Inherits="SimpleWeb.MyFirstWeb" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title></title>
    </head>
    <body>
        <!--获取前台页面的程序集位置-->
        <%=this.GetType().Assembly.Location %>
        <form id="form1">
        <div>
        <input type="text" name="txtName"/>
            <input type="submit" id="btnClick"/>
        </div>
        </form>
    </body>
    </html>

    后台代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace SimpleWeb
    {
        public partial class MyFirstWeb : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                Response.Write("Page_Load方法的开始<br/>");
                Response.Write("Page_Load方法的结束<br/>");
            }
        }
    }

    一个前台页面文件,在第一次被访问时,会被编译成一个类

    前台页面会被编译成前台页面类myfirstweb_aspx继承于后台页面类MyFirstWeb.cs

    发现前台类实现了IRequesSessionState:要取出Session中值,需要改接口
    又实现了IHttpHandler:因为后台类继承于Page,Page已经实现了该接口,此处只为方便阅读而已
    public class myfirstweb_aspx : MyFirstWeb, IRequiresSessionState, IHttpHandler
    {
        // Fields
        private static object __fileDependencies;
        private static bool __initialized;
        private static MethodInfo __PageInspector_BeginRenderTracingMethod;
        private static MethodInfo __PageInspector_EndRenderTracingMethod;
        private static MethodInfo __PageInspector_SetTraceDataMethod;
    
        // Methods
        static myfirstweb_aspx();
        [DebuggerNonUserCode]
        public myfirstweb_aspx();
        [DebuggerNonUserCode]
        private HtmlHead __BuildControl__control2();
        [DebuggerNonUserCode]
        private HtmlMeta __BuildControl__control3();
        [DebuggerNonUserCode]
        private HtmlTitle __BuildControl__control4();
        [DebuggerNonUserCode]
        private void __BuildControlTree(myfirstweb_aspx __ctrl);
        private void __PageInspector_BeginRenderTracing(object[] parameters);
        private void __PageInspector_EndRenderTracing(object[] parameters);
        private static MethodInfo __PageInspector_LoadHelper(string helperName);
        private void __PageInspector_SetTraceData(object[] parameters);
        private void __Render__control1(HtmlTextWriter __w, Control parameterContainer);
        [DebuggerNonUserCode]
        protected override void FrameworkInitialize();
        [DebuggerNonUserCode]
        public override int GetTypeHashCode();
        [DebuggerNonUserCode]
        public override void ProcessRequest(HttpContext context);
    
        // Properties
        protected HttpApplication ApplicationInstance { get; }
        protected DefaultProfile Profile { get; }
    }

    后台页面类MyFirstWeb.cs,如下

    public class MyFirstWeb : Page
    {
        // Fields
        protected HtmlForm form1;
    
        // Methods
        protected void Page_Load(object sender, EventArgs e)
        {
            base.Response.Write("Page_Load方法的开始<br/>");
            base.Response.Write("Page_Load方法的结束<br/>");
        }
    }

    -------------------------------------------------------------开始分析源码-----------------------------------------------------------------------------------

    1.当在浏览框中输入Localhost:MyFirstWeb.aspx,按回车的时候,

    在请求管道的第8个事件,创建了与请求名同名的页面类对象myfirstweb_aspx.cs,

    然后将该页面类对象保存到HttpContext中的RemapHandler中。

    接着在管道的第11个事件和12个事件之间,调用页面对象的PR方法,

    因为前台页面类继承于后台类,而后台类有继承于Page类,所以实际调用的是Page类的PR方法。

    private void ProcessRequest()
    {
        Thread currentThread = Thread.CurrentThread;
        CultureInfo currentCulture = currentThread.CurrentCulture;
        CultureInfo currentUICulture = currentThread.CurrentUICulture;
        try
        {
            this.ProcessRequest(true, true);
        }
        finally
        {
            this.RestoreCultures(currentThread, currentCulture, currentUICulture);
        }
    }

    1.1继续调用它的重载函数的PR方法

    this.FrameworkInitialize(); 表示调用当前对象的FI方法,当前对象就是前台页面类,那么我们就转到前台页面类的FI方法看看;
    protected override void FrameworkInitialize(); 发现在前台页面类中,重写了其父类的FI方法
    private void ProcessRequest(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)
    {
        if (includeStagesBeforeAsyncPoint)
        {
            this.FrameworkInitialize();
            base.ControlState = ControlState.FrameworkInitialized;
        }
        bool flag = this.Context.WorkerRequest is IIS7WorkerRequest;
        try
        {
            try
            {
                if (this.IsTransacted)
                {
                    this.ProcessRequestTransacted();
                }
                else
                {
                    this.ProcessRequestMain(includeStagesBeforeAsyncPoint, includeStagesAfterAsyncPoint);
                }
                if (includeStagesAfterAsyncPoint)
                {
                    flag = false;
                    this.ProcessRequestEndTrace();
                }
            }
            catch (ThreadAbortException)
            {
                try
                {
                    if (flag)
                    {
                        this.ProcessRequestEndTrace();
                    }
                }
                catch
                {
                }
            }
            finally
            {
                if (includeStagesAfterAsyncPoint)
                {
                    this.ProcessRequestCleanup();
                }
            }
        }
        catch
        {
            throw;
        }
    }

    2.FI方法,代码如下

    this.__BuildControlTree(this); 将前台页面对象作为参数传入,开始创建控件树
    [DebuggerNonUserCode]
    protected override void FrameworkInitialize()
    {
        base.FrameworkInitialize();
        this.__BuildControlTree(this);
        base.AddWrappedFileDependencies(__fileDependencies);
        base.Request.ValidateInput();
    }

    2.1.__BuildControlTree()代码如下

    myfirstweb_aspx __ctrl:那么_ctrl就是前台页面类;
    IParserAccessor __parser = __ctrl:将_ctrl转为接口类型,那么此时_parser就是前台页面类;
    __parser.AddParsedSubObject(__ctrl1):将_ctrl1添加到前台页面类中。
                                                问题一:_ctrl1是什么类型?还有它被添加到前台页面类的哪个成员中?
    [DebuggerNonUserCode]
    private void __BuildControlTree(myfirstweb_aspx __ctrl)
    {
        this.InitializeCulture();
        HtmlHead __ctrl1 = this.__BuildControl__control2();
        IParserAccessor __parser = __ctrl;
        __parser.AddParsedSubObject(__ctrl1);
        __ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Render__control1));
    }

    2.1.1.__BuildControl__control2();代码如下

    HtmlHead __ctrl = new HtmlHead("head"):创建一个head标签,并添加到前台页面类中;
    HtmlMeta __ctrl1 = this.__BuildControl__control3():设置meta的属性,并添加到head中;
    HtmlTitle __ctrl2 = this.__BuildControl__control4():设置标题,并返回标题,然后添加到前台页面对象中;
    [DebuggerNonUserCode]
    private HtmlHead __BuildControl__control2()
    {
        HtmlHead __ctrl = new HtmlHead("head");
        HtmlMeta __ctrl1 = this.__BuildControl__control3();
        IParserAccessor __parser = __ctrl;
        __parser.AddParsedSubObject(__ctrl1);
        HtmlTitle __ctrl2 = this.__BuildControl__control4();
        __parser.AddParsedSubObject(__ctrl2);
        object[] CS$0$0001 = new object[5];
        CS$0$0001[0] = __ctrl;
        CS$0$0001[2] = 180;
        CS$0$0001[3] = 0x79;
        CS$0$0001[4] = false;
        this.__PageInspector_SetTraceData(CS$0$0001);
        return __ctrl;
    }

    2.1.2.SetRenderMethodDelegate(new RenderMethod());调用一个委托,RenderMethod代码如下

    __w.Write:生成的代码写入了一个字符数组中(详情看超链接,文章后续会发布),当输出的时候,也是按写入时的顺序;
    __w.Write(base.GetType().Assembly.Location):很熟悉,就是我们在前台中写的C#代码,照样写入到字符数组中;
    parameterContainer.Controls[0].RenderControl(__w):在控件容器中找到第一个控件,然后调用它的RenderControl方法,
                                                                                                       在开始创建控件树时,发现第一个被添加到控件容器的是HTMLHead
    RenderControl(__w):也是吧代码写到字符数组中,不信自己看看源码
    private void __Render__control1(HtmlTextWriter __w, Control parameterContainer)
    {
        this.__PageInspector_BeginRenderTracing(new object[] { __w, "/MyFirstWeb.aspx", 0x70, 0x44, true });
        __w.Write("
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    ");
        this.__PageInspector_EndRenderTracing(new object[] { __w });
        parameterContainer.Controls[0].RenderControl(__w);
        this.__PageInspector_BeginRenderTracing(new object[] { __w, "/MyFirstWeb.aspx", 0x12d, 0x27, true });
        __w.Write("
    <body>
        <!--获取前台页面的程序集位置-->
        ");
        this.__PageInspector_EndRenderTracing(new object[] { __w });
        this.__PageInspector_BeginRenderTracing(new object[] { __w, "/MyFirstWeb.aspx", 340, 0x26, false });
        __w.Write(base.GetType().Assembly.Location);
        this.__PageInspector_EndRenderTracing(new object[] { __w });
        this.__PageInspector_BeginRenderTracing(new object[] { __w, "/MyFirstWeb.aspx", 0x17a, 0xa7, true });
        __w.Write("
        <form id="form1" >
        <div>
        <input type="text" name="txtName"/>
            <input type="submit" id="btnClick"/>
        </div>
        </form>
    </body>
    </html>
    ");
        this.__PageInspector_EndRenderTracing(new object[] { __w });
    }

    ---------------------------------------------------------------问题解答--------------------------------------------------------------------------------------

    问题一:_ctrl1是什么类型?还有它被添加到前台页面类的哪个成员中?

    _ctrl1是前台页面类型,那么前台页面又是什么类型

    myfirstweb_aspx继承于MyFirstWeb;

    MyFirstWeb继承于Page;

    Page继承于TemplateControl;(那么也可以说Page类也是一个控件)

    TemplateControl继承于Control;

    Control中有个只读属性,类型是控件集合类型:public virtual ControlCollection Controls { get; }

    那么一切问题都解决了,通过创建控件树,创建了一个个控件,同时将这些控件依次添加到前台页面的控件集合中,然后依次调用控件的RenderControl方法,将结果添加到字符数组中,然后将字符数组输出给HttpRuntime,然后传给iis,最后返回给浏览器,浏览器在根据接收到的结果,渲染界面,这就是我们最终看到的。

    image

    源码如下,就是按照字符数组中先后添加的代码显示到界面。为什么Page_Load中的数据先输出,请看超链接,文章后续会发布

    Page_Load方法的开始<br/>Page_Load方法的结束<br/>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>
    
    </title></head>
    <body>
        <!--获取前台页面的程序集位置-->
        D:UsersKimismeAppDataLocalTempTemporary ASP.NET Files
    oot5f14d39c6593da16App_Web_4br2rhb1.dll
        <form id="form1" >
        <div>
        <input type="text" name="txtName"/>
            <input type="submit" id="btnClick"/>
        </div>
        </form>
    
    <!-- Visual Studio Browser Link -->
    <script type="application/json" id="__browserLink_initializationData">
        {"appName":"InternetExplorer","requestId":"6cd255e00ebe439facbd972bb23ed352"}
    </script>
    <script type="text/javascript" src="http://localhost:1090/86ceaccf0cf9404491a3a03bf9ab677a/browserLink" async="async"></script>
    <!-- End Browser Link -->
    
    </body>
    </html>
    更多精彩内容请看:http://www.cnblogs.com/2star
  • 相关阅读:
    RadioButton练习(android)
    关于 RArrayFixFlat 与 RArray 与 CArrayPtrFlat 的测试
    How do I add an attachment to the message
    Grid View
    android 布局文件属性说明(转)
    File 存储(android)
    How to Make an HTTP Connection Using TCP/IP with RSocket
    使用RHTTPTransaction后产生CONE 36 Panic的解决办法
    SharedPreferences 存储(android)
    对话框的练习(android)
  • 原文地址:https://www.cnblogs.com/kimisme/p/4366911.html
Copyright © 2011-2022 走看看