ASP.NET05

本文总阅读量:
  1. 1. 创建缩略图
  2. 2. WebForm介绍
    1. 2.1. 深入理解aspx
  3. 3. IsPostBack
    1. 3.1. 验证
    2. 3.2. 如何实现的
    3. 3.3. 总结
  4. 4. ViewState

创建缩略图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var file = context.Request.Files[0]; 
//从上传图片创建大图
using (var bigImage = Image.FromStream(file.InputStream))
{
//等比创建小图
using (var smallImage = new Bitmap(200, 200 * bigImage.Height / bigImage.Width))
{
//创建画布将大图画入小图
using (var graphics = Graphics.FromImage(smallImage))
{
graphics.DrawImage(bigImage, 0, 0, smallImage.Width, smallImage.Height);
}
//保存
bigImage.Save(context.Server.MapPath(Guid.NewGuid() + "_big.jpg"));
smallImage.Save(context.Server.MapPath(Guid.NewGuid() + "_small.jpg"));
}
}

WebForm介绍

WebForm分为两个文件aspx和aspx.cs

aspx是页面模板,是页面描述文件,就是html+js+css的内容,和aspx.cs结合的更好,不用像一般处理程序那样程序员自己去输出HTML字符串或读取填充模板,控件都是定义在aspx中,内联的JavaScript、CSS也是写在aspx中的

前台页面上的@Page指令集。

服务端的C#代码是定义在aspx.cs中。aspx控制页面长相,cs控制程序逻辑,这种“前aspx后cs”的方式就被称为CodeBehind(代码后置)。

强调:后台页面可以把Page_Load看成是WinForm里的Load事件(“最先运行”)。

1.直接在后台通过Response.Write(“内容”);

  • aspx中也可以访问cs中定义的非私有的成员
  • 缺点:全都输出在页面的最上面。

2.使用<%%>在前台页面指定输出。

  • 可以编写复杂的C#代码, for等所有C#代码都可以写在aspx中

如: <%=UserName %> <%=SayHello(); %> <%if (UserName == “aaa”) { UserName = “bbb”; } %>

深入理解aspx

创建一个webform,对应的aspx.cs:

1
2
3
4
5
6
7
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
}

可以看到它集成System.Web.UI.Page,转到page元数据看到

1
public class Page : TemplateControl, IHttpHandler

Page继承自IHttpHandler,可以得出其实Page就是一个进一步封装的类,这时候我向class WebForm1中添加protected字段

1
protected int _num = 10;

aspx页面添加一句

1
<%=_num %>

运行可以看到10出现在html页面,为什么aspx可以访问cs里面的内容呢,看aspx头部有一个Inherits="_43.WebForm1"从字面上看,它是再说继承自_43.WebForm1,事实上aspx编译之后确实如此,

为了证明这一点,我向aspx里添加一句并拖一个控件进去,为了获取页面编译完成后dll的位置

1
2
<asp:Button ID="Button1" runat="server" Text="Button" />
<%=System.Reflection.Assembly.GetExecutingAssembly().Location %>

同时往pageload中添加

1
2
3
4
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(System.Reflection.Assembly.GetExecutingAssembly().Location);
}

html显示的是

1
2
C:\Users\luox78\AppData\Local\Temp\Temporary\ASP.NET\Files\root\2d000352\67fdd243\assembly\dl3\fd7cca4a\cf2ad37e_aea1d301\43.dll
10 Button C:\Users\luox78\AppData\Local\Temp\Temporary\ASP.NET\Files\root\2d000352\67fdd243\App_Web_amvk3cjo.dll

分别用reflector打开,看到cs派生类里是ASP.webform1_aspx,而page页面程序集ASP命名空间下就是webform1_aspx,所以aspx页面可以访问cs里面的字段可以解释了,这时候打开ASP.webform1_aspx里面有一个方法

https://luox78.github.io/images/cs_dll.png

https://luox78.github.io/images/aspx_dll.png

1
2
3
4
5
6
7
8
[DebuggerNonUserCode]
protected override void FrameworkInitialize()
{
base.FrameworkInitialize();
this.__BuildControlTree(this);
base.AddWrappedFileDependencies(__fileDependencies);
base.Request.ValidateInput();
}

this.__BuildControlTree(this);这句代表aspx里面的所有空间都被编译成了控件树,点开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[DebuggerNonUserCode]
private void __BuildControlTree(webform1_aspx __ctrl)
{
this.InitializeCulture();
LiteralControl control = this.__BuildControl__control2();
IParserAccessor accessor = __ctrl;
accessor.AddParsedSubObject(control);
HtmlHead head = this.__BuildControl__control3();
accessor.AddParsedSubObject(head);
LiteralControl control2 = this.__BuildControl__control6();
accessor.AddParsedSubObject(control2);
HtmlForm form = this.__BuildControlform1();
accessor.AddParsedSubObject(form);
LiteralControl control3 = this.__BuildControl__control7();
accessor.AddParsedSubObject(control3);
}

貌似里面创建很多html元素对象,这里我们就知道,所有的aspx页面里面的东西都会被编译成对应的对象,这时候回顾一下aspx页面body里面的内容

1
2
3
4
5
6
7
8
9
10
<body>
<form id="form1" runat="server">
<div>
<%=_num %>

<asp:Button ID="Button1" runat="server" Text="Button" />
<%=System.Reflection.Assembly.GetExecutingAssembly().Location %>
</div>
</form>
</body>

显示body,然后form,form里面有button,__BuildControlTree,里面也印证了这一点,我们打开创建form的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[DebuggerNonUserCode]
private HtmlForm __BuildControlform1()
{
HtmlForm form = new HtmlForm();
base.form1 = form;
form.ID = "form1";
Button button = this.__BuildControlButton1();
IParserAccessor accessor = form;
accessor.AddParsedSubObject(button);
form.SetRenderMethodDelegate(new RenderMethod(this.__Renderform1));
object[] parameters = new object[5];
parameters[0] = form;
parameters[2] = 0x131;
parameters[3] = 0x20;
parameters[4] = false;
this.__PageInspector_SetTraceData(parameters);
return form;
}

里面设置了form的一些属性同时创建了button,此时我们往html添加新的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<body>
<% for (int i = 0; i < 10; i++)
{%>
<h1>nihao</h1>
<% } %>
<form id="form1" runat="server">
<div>
<%=_num %>
<asp:Button ID="Button1" runat="server" Text="Button" />
<%=System.Reflection.Assembly.GetExecutingAssembly().Location %>
</div>
</form>
</body>

添加了一个循环以便我们查看dll里面如何处理C#代码的,编译之后发现__BuildControlTree里面多了一句

__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Render__control1));

点开 _Render_control1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private void __Render__control1(HtmlTextWriter __w, Control parameterContainer)
{
int num2;
object[] parameters = new object[] { __w, "/WebForm1.aspx", 160, 0x44, true };
this.__PageInspector_BeginRenderTracing(parameters);
__w.Write("\r\n\r\n<!DOCTYPE html>\r\n\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
object[] objArray2 = new object[] { __w };
this.__PageInspector_EndRenderTracing(objArray2);
parameterContainer.Controls[0].RenderControl(__w);
object[] objArray3 = new object[] { __w, "/WebForm1.aspx", 0x162, 14, true };
this.__PageInspector_BeginRenderTracing(objArray3);
__w.Write("\r\n<body>\r\n ");
object[] objArray4 = new object[] { __w };
this.__PageInspector_EndRenderTracing(objArray4);
object[] objArray5 = new object[] { __w, "/WebForm1.aspx", 0x170, 0x2c, false };
this.__PageInspector_BeginRenderTracing(objArray5);
for (int i = 0; i < 10; i = num2 + 1)
{
object[] objArray6 = new object[] { __w };
this.__PageInspector_EndRenderTracing(objArray6);
object[] objArray7 = new object[] { __w, "/WebForm1.aspx", 0x19c, 0x1a, true };
this.__PageInspector_BeginRenderTracing(objArray7);
__w.Write("\r\n <h1>nihao</h1>\r\n ");
object[] objArray8 = new object[] { __w };
this.__PageInspector_EndRenderTracing(objArray8);
object[] objArray9 = new object[] { __w, "/WebForm1.aspx", 0x1b6, 7, false };
this.__PageInspector_BeginRenderTracing(objArray9);
num2 = i;
}
object[] objArray10 = new object[] { __w };
this.__PageInspector_EndRenderTracing(objArray10);
parameterContainer.Controls[1].RenderControl(__w);
object[] objArray11 = new object[] { __w, "/WebForm1.aspx", 0x2c1, 20, true };
this.__PageInspector_BeginRenderTracing(objArray11);
__w.Write("\r\n</body>\r\n</html>\r\n");
object[] objArray12 = new object[] { __w };
this.__PageInspector_EndRenderTracing(objArray12);
}

看到for循环直接在里面,原来C#是直接和html元素一起编译成方法,最后转换成元素对象的,这时候或许你会有疑问cs里面是如何访问这些控件的,查看cs的dll可以看到

1
2
3
4
5
6
7
8
9
10
11
public class WebForm1 : Page
{
protected int _num = 10;
protected Button Button1;
protected HtmlForm form1;

protected void Page_Load(object sender, EventArgs e)
{
base.Response.Write(Assembly.GetExecutingAssembly().Location);
}
}

一旦你在aspx中创建了控件,cs里面就会有对应的protected字段(在designer.cs中),cs里对控件属性的修改继承自他的aspx的那个类会进行相应的更改,并将它反应到最终生成的页面上

总结:

https://luox78.github.io/images/IHttpHandler.png

IsPostBack

用于判断是第一次get页面还是post回发

验证

cs里pageload时

1
2
3
4
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(this.IsPostBack);
}

aspx中(aspx中form里面的button控件只会生成submit不会生成button)

1
2
3
<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" />
</form>

浏览会看到只有第一次get是false,回发的都是true

如何实现的

既然服务器控件生成的是html form那我自己写一个

1
2
3
<form id="form1" method="post" action="WebForm3.aspx">
<input type="submit" name="name" value="tijiao" />
</form>

cs里面跟上面一样,这时候运行会发现永远都是false,浏览器查看source我们就可以看出问题,runat serve的html里面多出了很多隐藏域,先将结果 IsPostBack是通过form中的隐藏域提交给服务器,如果没有接受到,那就是第一次请求,收到了肯定是回发。同时引出我们的下一部分viewstate

总结

1.IsPostBack用来判断表单是否是回发。(不是第一次请求),是点击表单的提交按钮回发过来的。是否是回发与get请求还是Post请求无关。但是一般情况下回发都是Post请求。一般Get请求都是第一次加载。

2.只有当使用服务器端表单<form runat="server">IsPostBack才可以使用。如果使用客户端表单,则IsPostBack永远都是False.因为当使用服务器端表单的时候会自动生成一个隐藏域,才该隐藏域中,服务器写入了一些内容,通过这些内容就可以判断是否是回发。如果使用的是普通html表单,则需要自己写代码来判断是否是回发。

3.IsPostBack的使用方式,为什么要使用IsPostBack

4.用处:使用IsPostBack可以知道是不是第一次请求,通过viewstate可以将第一次加载的数据停留在页面中减少数据加载的次数。避免了每次点击按钮回发都重新加载一次数据。

ViewState

viewstate(视图状态),顾名思义就是view的aspx空间的值状态

pageload中添加

1
ViewState["key"] = "nihao";

生成html里面有一个隐藏域为viewstate

1
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="P2yIH8jxqJKNyRGQn/BloDXHiGVvbfXBTzveFGTePfqct88mOSTSDiAJmfi3kLBaX+RRjSBf0RgEBmgfYTh1nQOXlqCGoRY2ccoHhM5M+buITfYkgxbsmXLRjBckuKji" />

value里面的值中就包含了nihao,下次解析的时候,我们不需要再次向页面传值也会显示,cs中的事件里面的改值就是通过这样实现的

缺点: 加大网站的流量、降低访问速度、机密数据放到表单中会有数据欺骗等安全性问题。

禁用ViewState :在asp顶部添加EnableViewState=”false”

1
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="_43.WebForm2" EnableViewState="false"%>