20110611 DiscuzNT代码研究(2)
pdf下载:http://download.youkuaiyun.com/source/3357916
1. 说明
1) 本文分析将按照每个项目进行分析,每个项目建立文件大纲进行分析,同时会引申一些相关的内容知识。
本节分析文件:
Discuz.Web/install/index.aspx |
2) 本节对部分内容会进行详细说明,以后章节将不再重复。
3) 本文不保证所有的用语都是标准的,如有语误,或者打错字,欢迎指正,可发邮件给我:cfqlilei@139.com(务必说明你是谁哦,算是认识一下,呵呵)
4) 有兴趣可关注本人博客:
优快云: http://blog.youkuaiyun.com/cfqlilei
博客园: http://www.cnblogs.com/wesoft/
51CTO: http://cfqlilei.blog.51cto.com/
2. index.aspx
2.1. 代码分析方法
1) 截图
2) 分析类成员(UML)
3) 分析类成员的实现和作用(深入源代码)
2.2. 截图
2.3. 分析类
从代码的前段,可以看出index.aspx页面没有相应的cs文件,本页面将在被浏览器请求的时候,自动编译一个继承与Page类的页面出来。
为了好分析,我们假设生成的类为index.aspx类
index.aspx的第一行,置顶了本页面的编译语言为C#
<%@ Page Language="C#"%> |
index.aspx的C#代码是在<script runat="server">…</script>体现出来。
2.4. 分析类成员
我们为_Index_Page类画一个UML图,借助“EnterpriseArchitect”工具,非常不错的一个UML建模工具。
从UML类图中可以看出,index.aspx基本上就是一个Page_Load方法,两个字段,这个方法和字段主要做什么作用呢?
2.5. 字段
2.5.1. httpModuleTip
提前说明:因为在源代码中加入注释等原因,截图中的行号与实际源代码的行号可能不一致。 |
该字符串主要是为了做“模块提示”信息
如果在web.config文件中不存在相应的节点,则提示相应信息。
我们稍微修改一下判断代码,即可看到提示效果,修改位置如下:
由于在判断条件中,都是用来“或”,随便改一个地方,判断条件不成立,就体会提示信息,提示信息放在哪里呢?
运行效果如下:
2.5.2. Msg
从对httpModuleTip的分析,我们看出,最终要显示在页面的信息就是通过Msg来显示出来。
显示方法有两种:
方法一:<%=msg%>
方法二:<%Response.Write(msg);%>
以上两种方法只能嵌入在Html标记中。
2.6. 方法
2.6.1. Page_Load
如何来分析Page_Load方法,实际上应该是事件方法,这个方法主要解决什么问题呢?
为了调试某个方法具体作用,有些时候我们需要在方法中添加一些测试方法,看看里面到底做些什么事情。
比如我们添加了一个测试方法“Response.Write(binfolderpath);”,并注释后续的代码,我们的目的是要只要HttpRuntime.BinDirectory返回的是什么样的值,返回结果值如下:
G:/WebServer/DiscuzNt360/source_files/Discuz.Web/bin/ |
即HttpRuntime.BinDirectory返回的是当前应用程序的 /bin 目录的路径。
2.6.1.1. 变量分析
我们先分析一下方法中的一些变量。
为了便于分析,我们把方法中涉及到的一些变量先浏览一遍。
2.6.1.1.1. bool isAssemblyInexistence
用于标识程序集是否存在
2.6.1.1.2. string binfolderpath = HttpRuntime.BinDirectory;
用于存储bin文件夹目录
binfolderpath=G:/WebServer/DiscuzNt360/source_files/Discuz.Web/bin/ |
2.6.1.1.3. string[] assemblylist = new string[] { "Discuz.Aggregation.dll"…};
用于存储程序集名称,由于涉及多个程序集,所以要存储多个字符串信息,这里采用字符串数组存储。
2.6.1.1.4. ArrayList inexistenceAssemblyList = new ArrayList();
用于存储“不存在的程序集名称”,假如“Discuz.Aggregation.dll”不存在,则该字符串会被存储在inexistenceAssemblyList中。
2.6.1.1.5. string xPath1 = "/configuration/system.web/httpModules";
用于存储一个xPath字符串,该字符串将被用于在XML查找相应的节点,如以上初始化"/configuration/system.web/httpModules",可以被用于检索如下类型的XML节点。
<configuration> <system.web> <httpModules> … </httpModules> </system.web> </configuration> |
本节中,用于检索web.config文件中的节点信息,我们看看web.config文件
2.6.1.1.6. System.Xml.XmlDocument webConfig = new System.Xml.XmlDocument();
创建一个XML对象,以便对XML进行操作,如何指定要操作的XML文件呢?就是要指定文件路径即可。
用XmlDocument对象的Load方法即可,代码如下:
这里指定了要操作的XML路径为:应用程序目录下的web.config。
如果获取应用程序目录,采用binfolderpath.Replace("bin//","")方法,该方法把“bin/”替换为空,即
binfolderpath=G:/WebServer/DiscuzNt360/source_files/Discuz.Web/bin/ |
替换后效果:
binfolderpath=G:/WebServer/DiscuzNt360/source_files/Discuz.Web/ |
于是web.config路径为
binfolderpath=G:/WebServer/DiscuzNt360/source_files/Discuz.Web/web.config |
2.6.1.1.7. System.Xml.XmlNode node1 = webConfig.SelectSingleNode(xPath1);
用于代表一个XML的节点,通过XmlNode对象,可以获取该节点和子节点的所有信息。
这里主要是要返回web.config文件中
<configuration> <system.web> <httpModules> (这里的第一个节点) </httpModules> </system.web> </configuration> |
即:
如何获取一个XML文件中节点的对象,可以采用如下方法,我们通过VS的帮助文件一下XmlDocument对象的信息。
我们发现XmlDocument有以下几个方法:
通过以上方法,可以获取:
1) 满足查询条件的节点列表,比如SelectNodes方法返回XmlNodeList对象。
2) 满足查询条件的第一个节点,比如SelectSingleNode方法返回XmlNode对象。
2.6.1.2. 方法主要功能
分析了主要字段后,我们在回头看看整体。
该方法主要做以下工作:
1) 检验dll文件在bin文件夹中是否存在
2) 检验web.config中是否存在需要的节点信息
3) 如果检验不通过,则提示相应信息,以便调整
4) 如果检验通过,则跳转到install.asp页面
2.6.1.3. 方法实现关键点
1) 通过assemblylist来存储需要检验的dll程序集信息
学习点: l 如何初始化数组 |
2) 然后遍历assemblylist中的信息,检查文件是否存在,如果不存在,则设置isAssemblyInexistence为true(表示dll文件不存在),并且在inexistenceAssemblyList中增加相应的dll文件名称,那么通过inexistenceAssemblyList可以知道哪些dll文件是不存在的。
学习点: l 如何创建数据列表:new ArraryList() l 如何为数组列表添加元素:Add方法 l 如何判断文件是否存在:System.IO.File.Exists(路径) l 如何获取文件路径:HttpRuntime.BinDirectory+“Discusz.Cache.dll” l 如何变量数组:foreach的使用 |
3) 如果dll文件部分或者全部不存在(isAssemblyInexistence为true),那么就遍历inexistenceAssemblyList,列出哪些dll文件不存在。
学习点: l <li>:Html标记,可显示列表 |
4) 然后在检查web.config文件中是否存在“/configuration/system.web/httpModules”和“/configuration/system.webServer/modules”节点信息,主要是为了保证将来的使用。
这里分为几个步骤:
a) 先判断web.config文件是否存在:System.IO.File.Exists
b) 先获取Xml对象:System.Xml.XmlDocument对象,Load方法
c) 再获取node对象: XmlDocument对象的SelectSingleNod方法
d) 然后判断node是否正常,以此来检验
实现分析:
在判断节点是否ok,这里用如“node1==null”,为什么要这么用呢?主要是为了提高效率,因为当“node1==null”的话,后续的判断条件就不用校验了,效率就高了。
node1.ChildNodes.Count <= 0,也是同样原理。
学习点: l 如何获取XML对象:System.Xml.XmlDocument对象,Load方法 l 如何获取Node对象:XmlDocument对象的SelectSingleNod方法 l 如何判断节点是否存在: node1 == null || node1.ChildNodes.Count <= 0 || node1.InnerXml.IndexOf("Discuz.Forum.HttpModule") < 0 |
5) 如果不存在,则同样提示信息,不过这里就不像dll文件那样提示搞得那么复杂,就直接httpModuleTip字符串信息提示就过去了,知道就行了。
6) 当检验都通过的话,那么isAssemblyInexistence就为false,这是就跳转到install.aspx。
学习点: l 如何跳转页面:Respone.Redirect(页面地址) |
2.7. 补充知识点
1) HttpUtility.HtmlEncode
将字符串转换为 HTML 编码的字符串,比如当字符串中包含特殊字符,如“<>,/,/”等等,如果我们希望完整通过HTML显示的话,就要用HttpUtility.HtmlEncode。
2) System.Xml.XmlNode node1 = webConfig.SelectSingleNode(xPath1);
XmlNode.SelectSingleNode 方法 选择匹配 XPath 表达式的第一个 XmlNode |
XmlNode对象对应一个XML的节点(元素)
XmlNode 类在System.Xml(在 System.Xml.dll 中)命名空间中
3) Response.Write("<br>" + HttpUtility.HtmlEncode(node1.InnerXml));
node1.InnerXml表示获取node1节点中的内部Xml,包含了内部节点的信息
如果用node1.InnerText,只是显示该节点和子节点的标记文本(子节点文本)。
如果用node1.OuterXml,则显示该节点和子节点的标记(本节点+子节点)。
如果用node1.InnerXml,则只是显示子节点的标记(子节点)。
4) Response.Write("<br>" +node1.InnerXml);
5) Response.Write("<br>" + node1.InnerXml.IndexOf("Discuz.Forum.HttpModule").ToString());
2.8. XML学习(XML的结构)
从下图可以看出,XML由以下几个元素组成:
1) 元素(根元素、子元素):XmlNode对象
2) 属性:
用XmlNode. Attributes可以获取到属性列表(XmlAttributeCollection),可以通过XmlAttributeCollection. XmlAttribute (string)方法获取置顶属性的值。
3) 文本
用Xml.Node. OuterXml可以获取该节点和子节点的标记
用Xml.Node. InnerText可以获取或设置该节点和子节点的标记
用Xml.Node.Value,不同NodeType返回的Value不一致
(本节完毕)