ASP.NET中aspx页面runat=server的本质(Essensial of runat=”server” in ASP.NET)
今天同事问我一个“神奇”的问题,另一个同事“神奇”地找出了问题但无法解释,归咎于一种“习惯”或者“下次注意”。现在我把问题描述一下,并做一些解释。
我的同事先是在现有工程中新加了一个aspx页面,然后从现有的执行正确的页面的源码中copy了一部分内容到新页面的相应位置,但却无意中留下了runat=”server”标签。具体代码还原如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebAppHeadRunatServer._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> <script runat="server">string str = "mypath"; </script> <head runat="server"> <title><%="My title" %></title> <link rel="Stylesheet" href="<%= str %>/a.css" /> <script language="javascript" type="text/javascript" src="<%=str %>/a.js"></script> </head><body></body></html>
1、以上代码究竟会有哪些诡异的现象?
在代码没有出现问题的时候,我们总是不太在意runat=”server”的存在,即便在代码出现问题的时候,我们也很少会重视runat=”server”的问题,因此当问题出现的时候我们总是用“经验”或者“尝试”去解决,却很少能够知根知底地了解它,因为它确实看起来太“小”了。
那么上面的代码究竟如何诡异呢?因为我的朋友始终没有注意到runat=”server”,因此当出现下面问题的时候,我们总是在比较两个文本的差异。
<head><title> My title</title><link rel="Stylesheet" href="<%= str %>/a.css" />
<script language="javascript" type="text/javascript" src="mypath/a.js"></script>
起初,我们认为是我们写错了,我们重复将正确位置的<%=str%>拷贝至出错的位置,但并非如我们所愿,使用断点调试,我们所跟到的str的值是正确的,但后续动作我们跟踪不到,因此我们开始相信“诡异”,当然,崇尚科学的我们也知道,这仅仅是我们暂时无法解决的。
2、为何在调试的时候,只有link里的href会出问题,而别的却不会?
当我们重复了3-4次之后,我们开始怀疑我们的人品,因为我同事说代码是从另一个页面上拷过来的,因此肉眼加事实告诉我们,这是一个特例,直到我们请另一个同事过来鉴证诡异之后,我们才决定去比对一下“代码是如何被拷过来”的,原来代码是被局部拷贝,影响代码的罪魁祸首是head处的runat=”server”。嗯,问题找到了,但发现问题的同事却无法解释,理由仅是,这样是不行的,我们都得把这个去掉。确实太牵强了,难道我们就不能解释一下?当然,求人不如求己,自己思考一下就很容易有结果了。
3、runat=”server”的时候到底发生了什么?
既然问题是从runat=”server”引起的,那么就得从它入手。runat=”server”这个标记,旨在aspx页面被编译的时候,用来标识我们页面上的html应该如何解释的。准确地说,aspx页面的生成原理是,aspx页面会被读入分析器,当一个HTML标签内不包含runat=”server”的时候,它将被当作字符串输出或者编译成new LiteralControl(“具体的文本”);
当遇到runat=”server”的时候,如果标签可以被转换为一个HtmlControl,则转换成HtmlControl,否则将会被解释为一个HtmlGenericControl对象,因为要转换成对象,所以会多出一些规则检查,假设没有runat="server",则你的所有字符都将被当作文本进行输出,但是如果加上runat="server",则所有的属性如果有对应的则转换成“属性=value”的模式,如果没有,则转换成SetAttribute("name", "value");的形式,因此如果id="",则会变成XXX.ID="",而此处的ID则需要满足一般的命名规范,以满足在别的地方直接以ID进行对象引用,也就是说必须是字母/下划线打头。对其他属性则没有过多严格的要求,但是对应的<%=str%>将只以文本进行输出,而不会替换为其值。
下面的类继承图展示了所有继承自HtmlControls的控件。
比如一个<head runat=”server”></head>
将被解析为:
HtmlHead head = new HtmlHead(“head”);HtmlTitle title = this.__BuildControl__control3();IParserAccessor accessor = head;accessor.AddParsedSubObject(title);
这里的AddParsedSubObject大致是如下代码:
public class Control
{
protected virtual void AddParsedSubObject(object obj)
{
Control child = obj as Control;
if (child != null)
{
this.Controls.Add(child);
}
}
}
也就是Controls.Add方法。
这里用增加输出委托的方式来进行一些HTML呈现的逻辑:
private HtmlTitle __BuildControl__control3()
{
HtmlTitle title = new HtmlTitle();
title.SetRenderMethodDelegate(new RenderMethod(this.__Render__control3));
return title;
}
private void __Render__control3(HtmlTextWriter __w, Control parameterContainer)
{
__w.Write("\r\n ");
__w.Write("My title");
}
4、那为何link的href会出错,而script则不会呢?
// 生成script
private void __Render__control2(HtmlTextWriter __w, Control parameterContainer){ parameterContainer.Controls[0].RenderControl(__w); parameterContainer.Controls[1].RenderControl(__w); __w.Write("\r\n\r\n <script language=\"javascript\" type=\"text/javascript\" src=\""); __w.Write(this.str); __w.Write("/a.js\"></script>\r\n\r\n "); parameterContainer.Controls[2].RenderControl(__w);}
// 生成HtmlLink
private HtmlLink __BuildControl__control4()
{
HtmlLink link = new HtmlLink();
((IAttributeAccessor) link).SetAttribute("rel", "Stylesheet");
link.Href = "<%= str %>/a.css";
return link;
}
很显然,link的Href是直接将页面上的文本进行赋值的,因此最终并没有使用str中的值去替代文本,而script中,str则是被直接输出的,因此script是可以的,而link则会出现问题。
5、去掉runat=”server”则解决问题,为什么?
因为去掉runat=”server”后,link标签将不再转换成HtmlLink,因此就不会调用link.Href属性去赋值,因此就不会出错了。
private void __Render__control1(HtmlTextWriter __w, Control parameterContainer){ __w.Write("\r\n\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd%5C%22>\r\n<html xmlns=\"http://www.w3.org/1999/xhtml%5C%22>\r\n\r\n"); __w.Write("\r\n\r\n<head>\r\n <title>\r\n "); __w.Write("My title"); __w.Write("</title>\r\n <link rel=\"Stylesheet\" href=\""); __w.Write(this.str); __w.Write("/a.css\" />\r\n\r\n <script language=\"javascript\" type=\"text/javascript\" src=\""); __w.Write(this.str); __w.Write("/a.js\"></script>\r\n\r\n "); parameterContainer.Controls[0].RenderControl(__w); __w.Write("\r\n</head>\r\n<body>\r\n "); parameterContainer.Controls[1].RenderControl(__w); __w.Write("\r\n</body>\r\n</html>\r\n");}
6、有什么特征?(结论)
准确地说,因为在runat=”server”下,编译器会将其中的所有属性的xxxx=yyyy的部分都首先转换成其Attribute,设置的方式通常有以下两种
a、通过SetAttribute("xxxx", "yyyy");
b、如果该HtmlControl含有该属性,则由其属性来设置,如head.Href=”yyyy”;
注意,这里不管yyyy是否是<%=mmm%>,一样会被直接当作文本输出。
但是,在正文中出现的将以__w.Write(this.str);的方式输出。
<form id="form1" runat="server" accept="<%=str %>"> <div><%=str %> </div> </form>
结论:在runat=”server”下的标签,如果可以转换成HtmlControl,那么它的Attribute将不能使用<%=str%>的方式输出,如果不能转换成HtmlControl,则没有具体要求。如果一定要使用<%=str%>的方式,则需要将其以及它的祖先节点上的runat=”server”去掉即可。但是,关于一个嵌套的结构是否会被自动提升为runat=”server”则是根据标准来制定的。比如将link标签放在head中,设置head为runat=”server”,则link会被转换成HtmlLink,但是将其放在<form runat=”server”>下则只会被当作文本输出。而在form下的控件则不会进行自动提升,如<form runat=”server”><input type=”button” /></form>则button将继续以文本的方式输出,遇到<%=str%>将被转换成__w.Write(str);。如果需要将其提升为HtmlInputButton控件,将显示指定其为<input runat=”server” type=”button” />。
编译下面的代码,并打开“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\”路径下的对应的程序集,用reflector反编译查看源代码,并验证以上规律。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebAppHeadRunatServer._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> <script runat="server"> string str = "mypath"; </script> <head runat="server"> <title><%="My title" %></title> <link rel="Stylesheet<%= str %>" href="<%= str %>/a.css" /> <input id="Button1" type="button" value="<%=str %>" /> <script language="javascript" type="text/javascript" src="<%=str %>/a.js"><%=str %><link rel="Stylesheet<%= str %>" href="<%= str %>/a.css" /></script> <meta content="volnet.cnblogs.com" name="<%=str %>-blog" runat="server" /></head><body> <form id="form1" runat="server" accept="<%=str %>"> <link rel="Stylesheet<%= str %>" href="<%= str %>/a.css" /> <div id="<%=str %>x">accept="<%=str %>"</div> <input type="button" value="<%=str %>" /> <input type="button" runat="server" value="<%=str %>" /> </form></body></html>
ASP.NET中aspx页面runat=server的本质(Essensial of runat=”server” in ASP.NET)相关推荐
- asp.net的aspx页面<% %>、<%@ %>、<%# %>、<%= %>、<%$ %>的用法
1. <%--exegesics--%> 注释 相当于<!----> 2. <% code%> 绑定后台代码块: //相当于写在后台的可执行代码 <form ...
- ASP.NET中.aspx文件和.aspx.cs文件的功能区别和特点
.aspx与aspx.cs区别特点和功能 1) 首先了解一下整个asp.net网站的结构特点 整个网站 aspx/cshtml:前台页面,区别是编译引擎不一样,后者在ASP.net MVC3中引入 . ...
- Asp.net中一个页面多个表单的解决方案
<form id="form1" runat="server"> <input name="TrueName" type= ...
- ASP.NET中实现页面间的参数传递 QueryString\Application\Session\Cookie
一.使用QueryString 使用QueryString在页面间传递值是一种非常常见的方法,我们在ASP中就常常用到. (1)优点和缺点 优点: 1.使用简单,对于安全性要求不高时传 ...
- ASP.net 中的页面继承实现和通用页面的工厂模式的实现
最近用.Net做web项目的时候遇到了一些问题,就是很多的页面的处理一样的,不一样的就是我们写的存储过程不同,为了考虑代码的重复利用和可维护性和可 扩展性,于是写了一个对于单据页面的工厂模式,采用界面 ...
- 用aspx开发html5页面,ASP.NET使aspx页面能接受HTML,asp的页面传送的文件-.NET教程,Asp.Net开发...
aspx接受aspx页面的文件很简单,用htmlinputfile,就可以了,但是如果接受html页面post的文件 就不怎么好办了,我仿照asp的方法做法如下,自己测试通过,拿出来给大家共享,可以限 ...
- ASP.NET 中处理页面“回退”的方法
我们在编写基于 ASP.NET 的应用程序时,如果代码执行出错或检测到异常,一般会提示用户"返回"或"回退",或者在多步操作.列表/详细的查看界面中,也会给用户 ...
- ASP.NET使aspx页面能接受HTML,asp的页面传送的文件
aspx接受aspx页面的文件很简单,用HtmlInputFile,就可以了,但是如果接受Html页面post的文件 就不怎么好办了,我仿照asp的方法做法如下,自己测试通过,拿出来给大家共享,可以限 ...
- asp.net 调用html页面,ASP.NET中HTML页面的访问验证设置方法
可能有很多朋友和我一样不会留意到这样的问题,在ASP.NET中,使用其自身提供的访问验证功能(表单验证.Passport 验证.Windows 验证),并不会对静态文件(如 html.图像文件.文本文 ...
最新文章
- 【java】牛客网刷题
- 儿科医生的眼泪,全被数据看见了
- 你玩的音游可能真是AI生成的,Love Live!工作室发了篇论文,用AI节省50%作谱时间...
- php 服务常量,php常量
- mysql事务变量_mysql学习四之事务、变量、触发器、函数、存储过程
- HTML——a标签实现空链接(禁止跳转)
- jstl与struts2 条件语句的区别
- css 一行显示_CSS笔记1
- LeetCode之Two Sum II - Input array is sorted
- 7-2 日期问题面向对象设计(聚合一) (35 分)
- 史上最严重数据车祸:100+车厂机密全曝光,通用丰田特斯拉统统中招
- Connect() 2016 大会的主题 ---微软大法好
- 专题九:Simulink系统仿真
- c语言下楼的题目,用C语言编写下面题目的程序:
- filezilla server mysql_使用FileZilla Server轻松搭建个人FTP服务器
- linux 磁盘坏道修复,linux系统下检测硬盘上的坏道和坏块
- 第四讲:学习理论(Learning Theory)
- shell 正则取出中间文本。
- 【Python】伪距单点定位
- 11-赵志勇机器学习-DBSCAN聚类
热门文章
- 王欣MT背后隐藏着怎样的心理学市场?
- 虚拟化(Citrix Netscaler)双因素身份认证解决方案
- docker运行项目脚本
- Android开发,使用Log打印日志,打印相同内容在Logcat中只能连续显示两次(遍历打印List中的内容,打印结果条数比List的size小)。
- 生鲜行业用新营销模式,为“冬令进补”造火围炉
- IDEA如何开始护眼模式
- Java:Random函数及其种子的作用
- 浅谈用VB6.0编写“特洛伊木马”程序
- harrynull.tech/cipher游记(分享通关工具和粗糙的通关过程)持续更新
- 2021辽宁省大学生程序设计竞赛