从源码看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#代码,照样写入到字符数组中; RenderControl(__w):也是吧代码写到字符数组中,不信自己看看源码 |
private void __Render__control1(HtmlTextWriter __w, Control parameterContainer)
{
this.__PageInspector_BeginRenderTracing(new object[] { __w, "/MyFirstWeb.aspx", 0x70, 0x44, true });
__w.Write("\r\n\r\n<!DOCTYPE html>\r\n\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
this.__PageInspector_EndRenderTracing(new object[] { __w });
parameterContainer.Controls[0].RenderControl(__w);
this.__PageInspector_BeginRenderTracing(new object[] { __w, "/MyFirstWeb.aspx", 0x12d, 0x27, true });
__w.Write("\r\n<body>\r\n <!--获取前台页面的程序集位置-->\r\n ");
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("\r\n <form id=\"form1\" >\r\n <div>\r\n <input type=\"text\" name=\"txtName\"/>\r\n <input type=\"submit\" id=\"btnClick\"/>\r\n </div>\r\n </form>\r\n</body>\r\n</html>\r\n");
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,最后返回给浏览器,浏览器在根据接收到的结果,渲染界面,这就是我们最终看到的。

源码如下,就是按照字符数组中先后添加的代码显示到界面。为什么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:\Users\Kimisme\AppData\Local\Temp\Temporary ASP.NET Files\root\5f14d39c\6593da16\App_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>
从源码看ASP.NET框架(一)-打造页面控件树的更多相关文章
- Asp.net页面生命周期详解任我行(2)-WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用
摘要 页面类是如何结合后台文件类生成整个页面的HTML的代码和后台输出的代码输出到浏览器中呢?这就牵扯到Asp.net页面生命周期中一个很重要的概念控件树.服务器以反射的方式创建了页面类对象 内容 我 ...
- asp.net原理笔记----页面控件类型,页面状况和asp.net编译过程
通过查看asp.net的整个生命周期之后 了解到在aspx的页面生命周期中 调用了BuildControlTree()方法生成页面控件树 之后再调用Rend()方法根据控件树生成html返回 aspx ...
- Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析
经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...
- Java并发包源码学习之AQS框架(三)LockSupport和interrupt
接着上一篇文章今天我们来介绍下LockSupport和Java中线程的中断(interrupt). 其实除了LockSupport,Java之初就有Object对象的wait和notify方法可以实现 ...
- Java并发包源码学习之AQS框架(一)概述
AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer这个类. 阅读Java的并发包源码你会发现这个类是整个java.util.con ...
- 从源码看JDK提供的线程池(ThreadPoolExecutor)
一丶什么是线程池 (1)博主在听到线程池三个字的时候第一个想法就是数据库连接池,回忆一下,我们在学JavaWeb的时候怎么理解数据库连接池的,数据库创建连接和关闭连接是一个比较耗费资源的事情,对于那些 ...
- 从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计
使用微信小程序开发已经很长时间了,对小程序开发已经相当熟练了:但是作为一名对技术有追求的前端开发,仅仅熟练掌握小程序的开发感觉还是不够的,我们应该更进一步的去理解其背后实现的原理以及对应的考量,这可能 ...
- AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架
目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Se ...
- Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构
Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构 目录 Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构 0x00 摘要 0x01 Alink设计原则 0x02 A ...
随机推荐
- CRC校验算法学习
原文:http://www.repairfaq.org/filipg/LINK/F_crc_v31.html 本文根据上述链接原文翻译而来,如有错误,忘广大网友互相帮忙纠正,谢谢! 1.前言: 1.0 ...
- B树、B-树、B+树、B*树介绍,和B+树更适合做文件索引的原因
今天看数据库,书中提到:由于索引是采用 B 树结构存储的,所以对应的索引项并不会被删除,经过一段时间的增删改操作后,数据库中就会出现大量的存储碎片, 这和磁盘碎片.内存碎片产生原理是类似的,这些存储碎 ...
- M - 小希的迷宫 并查集
上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了 ...
- Linux 安装 RabbitMQ
转载文章,地址:https://www.cnblogs.com/uptothesky/p/6094357.html 侵删!
- Ubuntu 16.04监控网络带宽软件
1.系统监控器已经自带了默认的监控功能,包括CPU.内存.带宽.进程等,但带宽的一些详情不能显示出来. 2.使用top命令进行监控进程 sudo top 3.安装Indicator-sysmonito ...
- SystemTapでMySQL 5.5のDisk I/Oを分析する
http://d.hatena.ne.jp/sh2/20111121 2010年1月の記事SystemTapでMySQLのDisk I/Oを分析するの続きです.以前作成したSystemTapスクリプト ...
- ORACLE EM的删除与创建
手动删除ORACLE 10G EM 使用emca可以手动配置em! 配置em的过程中有一个环节要特别主要: 不论使用dbca还是使用emca -deconfig dbcontrol db -repos ...
- what happens if we dont resolve or reject the promise
https://stackoverflow.com/questions/36734900/what-happens-if-we-dont-resolve-or-reject-the-promise I ...
- C++对象模型——继承体系下的对象构造(第五章)
5.2 继承体系下的对象构造 当定义一个object例如以下: T object; 时,实际上会发生什么事情呢?假设T有一个constructor(不论是由user提供或是由编译器合成),它会被调用. ...
- C# Json反序列化 C# 实现表单的自动化测试<通过程序控制一个网页> 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案) 大话设计模式:原型模式 C# 深浅复制 MemberwiseClone
C# Json反序列化 Json反序列化有两种方式[本人],一种是生成实体的,方便处理大量数据,复杂度稍高,一种是用匿名类写,方便读取数据,较为简单. 使用了Newtonsoft.Json,可以自 ...