自从 mvc3 被广泛的推进生产环境后,这个runat="server" 慢慢被人遗忘了。。。
asp.net 的 webForm 基于控件的 html 渲染过程是否还记得呢?是否还记得那 一坨坨的控件?
HtmlTextWriter 还有记得的吗?
那迷人的 Page的生命周期?
https://msdn.microsoft.com/zh-cn/library/ms178472.aspx
下面文章希望有所启发。。
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是必须存在的,下面的表格显示了可以设置runat=”server”的Html标签,否则将会出现“分析器错误”(分析器错误消息: 路径中具有非法字符。):
比如一个<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=”head”则解决问题,为什么?
因为去掉runat=”head”后,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\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\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);。如果需要将其提升为HtmlButton控件,将显示指定其为<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"的更多相关文章
-
ASP.Net中防止页面刷新重复提交的几种方法
[摘要] 目前很多网站都要提交页面插入或更新数据库,比如留言本,一个用户提交留言后,如果按F5,就会重新提交一遍留言,导致数据库出现两条一模一样的留言,本文介绍了几种防止页面刷新,导致重复提交数据的方 ...
-
Asp.Net中动态页面转静态页面
关于在Asp.Net中动态页面转静态页面的方法网上比较多.结合实际的需求,我在网上找了一些源代码,并作修改.现在把修改后的代码以及说明写一下. 一个是一个页面转换的类,该类通过静态函数Changfil ...
-
ASP.NET中实现页面间的参数传递
ASP.NET中实现页面间的参数传递 编写人:CC阿爸 2013-10-27 l 近来在做泛微OA与公司自行开发的系统集成登录的问题.在研究泛微页面间传递参为参数,综合得了解了一下现行页面间传参 ...
-
asp.net中父子页面通过gridview中的按钮事件进行回传值的问题
这两天写BS程序,遇到父子页面传值的问题,以前没写过web系统,用了几天时间才将问题解决,总结下记录下来: 问题描述: 父页面A中有一个gridview,每行6个列,有5列中均有一个按钮,单击按钮,会 ...
-
ASP.NET中实现页面间数据传递的方法
说到页面间数据传递,很多人都会想到通过像Session这样的全局变量,但是向Session中添加的东西太多会增加服务器的压力,页面间数据传递,数据的作用范围越小越好. ASP.NET页面间数据传递 ...
-
asp.net 6.aspx页面
1.aspx页面的头部 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Us ...
-
webform工程中aspx页面为何不能调用appcode文件夹下的类(ASP.NET特殊文件夹的用法)
App_code 只有website类型的工程才有效. App_Code 下创建的.cs文件仅仅是“内容”不是代码.你设置那个文件为“编译”就行了. 其他特殊文件夹 1. Bin文件夹 Bin文件夹包 ...
-
asp.net 中 .ASPX 与.CS文件的关系
.aspx文件继承自.cs文件 虽然一个 Web 窗体页由两个单独的文件组成,但这两个文件在应用程序运行时形成了一个整体.项目中所有 Web 窗体的代码隐藏类文件都被编译成由项目生成的动态链接库 (. ...
-
asp.net中iframe页面用jQuery向父页面传值
在asp.net页面有时一个页面会通过iframe嵌套另一个页面,下面的例子讲述的是被嵌套的iframe页面向父页传值的一种方式,用jQuery即可. iframe页面代码: <!DOCTYPE ...
随机推荐
-
Anaconda 安装 ml_metrics package
ml_metrics is the Python implementation of Metrics implementations a library of various supervised m ...
-
服务器上index.jsp变空
早上,前五分钟3台分别浏览了3台服务器,都是正常的,一会后台说其中一台打开页面是空白的,发现这台服务器上的index.jsp文件变成了空白.用其他服务器上的index.jsp文件覆盖,蹦出了另一个错误 ...
-
putty连接报NetWork error:connection refused
首先通过物理终端进入到linux上,手工检查ssh发现没运行 /etc/init.d/sshd status 使用rpm -V 命令可检查到ssh的软件包正常 /rpm -V openssh-serv ...
-
jquery.tagthis和jquery.autocomplete一起实现标签
目的 jquery.tagthis:http://www.dangribbin.co/jquery-tag-this/demo/ 使用tagthis控件实现标签的输入提醒功能,每个标签具有id和tex ...
-
【matlab】用matlab 保存带标记图像、图片的方法总结
最近看了一些用matlab对图形图片进行保存的帖子和资源,关于图像保存的方法给大家分享一下这些方法是大家所使用方法的一个总结. 如今常用的方法有三种printf,imwrite,saveas下面分别介 ...
-
Oracle LPAD/RPAD函数在处理中文时的注意事项
首先看下Oracle官方对函数的定义: The RPAD function returns an expression, right-padded to a specified length with ...
-
POJ 3159 Candies 解题报告(差分约束 Dijkstra+优先队列 SPFA+栈)
原题地址:http://poj.org/problem?id=3159 题意大概是班长发糖果,班里面有不良风气,A希望B的糖果不比自己多C个.班长要满足小朋友的需求,而且要让自己的糖果比snoopy的 ...
-
jQuery -&;gt; 获取/设置/删除DOM元素的属性
jQuery的属性操作很easy,以下以一个a元素来说明属性的获取/设置/删除操作 <body> <a>jquery.com</a> </body> 加 ...
-
div section article aside的理解
div 是一个大的容器 内部可以包含header main nav aside footer等标签 没有语义,多用于为脚本添加样式 section的语义比div语义强些,用于主题性比较强的内容,比如一 ...
-
关于win8/win8.1系统不能调节亮度的解决办法
有时候我们重装了win8系统之后开始可以调节亮度,但是再重新安装了显卡驱动之后发现不能调节亮度了,解决办法就是添加一项注册表. 下载地址:http://7xnarc.com1.z0.glb.cloud ...