ASP.NET站点性能提升-优化表单
客户端验证
ASP.NET验证控件
验证控件不只提供客户端的验证,也提供服务器端验证。如果页面上的任何一个验证控件验证不通过,page对象的IsValid属性值为false。
protected void btnSave_Click(object sender, EventArgs e) { if (!Page.IsValid) { return; } //Process Page ... }
开销
使用ASP.NET验证控件会使ASP.NET在.aspx页面上加载很多内联JavaScript代码,大概有5KB或压缩后1KB。
它也会使ASP.NET从服务器下载JavaScript文件,一共41KB(压缩后11KB)。但是,如果这些文件在浏览器被缓存,在第二次访问时,就不会再加载了。
使用jquery validator
略
异步提交表单
异步提交表单方式比较
Method | Overhead | Description |
Classic ASP.NET | Very High | Very easy to use. Causes full-page refresh, requiring ViewState to maintain state of each control. |
UpdatePanel control | High | Very easy and quick to use. No need to write JavaScript. |
Page Methods | High | Lets you call C#/VB code behind methods with a single line of JavaScript. |
Web Service | Medium | Lets you call web services with a single line of JavaScript. |
Generic Handler | Low | The JavaScript to call an ASP.NET Generic Handlers is a bit more involved. Provices most scope for performance improvements. |
WCF Data Services and the Entity Framework | Medium | Allows you to generate the server-side data access code using Visual Studio. |
UpdatePanel控件
使用UpdatePanel控件,ScriptManager控件会向页面加入内联JavaScript,并加载JavaScript库(大约90KB)。
页面方法
首先在页面顶端加入ScriptManager控件。这会在页面上生成调用后端方法的JavaScript代理对象。ScriptManager控件需要设置EnablePageMethods属性为true。
<body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="True" /> [System.Web.Services.WebMethod] public static string SaveForm(string title, string author, string price) { ... }
页面方法可以访问请求上下文,例如:
string userAgent = HttpContext.Current.Request.UserAgent;
从JavaScript中调用
PageMethods.SaveForm(title, author, price, onSuccess, onError); … function onSuccess(result) { … } function onError(result) { … }
result参数包含web方法返回值。
Web service
[WebMethod] public string SaveForm(string title, string author, string price) { ... } <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server" > <Services> <asp:ServiceReference Path="FormService.asmx" /> </Services> </asp:ScriptManager> FormService.SaveForm(title, author, price, onSuccess, onError, onTimeout); ... function onSuccess(result) { } function onError(result) { } function onTimeout(result) { }
Generic handler
Generic handler开销很小,并且允许异步访问数据库,这样可以更好地利用IIS工作线程。如果性能要优于易用性,generic handler是最好的选择。不像web services,generic handlers只暴露一个接口。
创建generic handler
public void ProcessRequest (HttpContext context) { if((context.Request.HttpMethod != "POST") || // to prevent cross site request forgery attacks (context.Request.ContentType != "application/json; charset=utf-8")) { context.Response.ContentType = "text/plain"; context.Response.Write("Access Denied"); return; } string json = RequestBody(context.Request); JavaScriptSerializer js = new JavaScriptSerializer(); FormData formData = js.Deserialize<FormData>(json); string message = Business.ProcessForm(formData.title, formData.author, formData.price); context.Response.ContentType = "text/plain"; context.Response.Write(message); }
FormData类:
private class FormData { public string title = null; public string author = null; public string price = null; }
跨站请求伪造攻击
为什么不允许GET请求,并要求content type是application/json; charset=utf-8可以阻止跨站请求伪造(Cross Site Request Forgery(CSRF))攻击。
在CSRF攻击中,访问者被欺骗执行一小段HTML发送一个未意识的请求到访问者已经登录的站点。例如,假设一个访问者登录了bank.com。登录操作使用bank.com在访问者的计算机上放置了一个cookie,记住访问者已经登录了。然后如果访问者被诱惑访问evil.com页面,这个页面可能包含一个对bank.com的攻击请求:
<img src="http://bank.com?withdraw=1000;sendto=evil" />
访问者的浏览器会发送一个到bank.com的请求。这个请求会包含说明访问者已经登录的cookie。所以,evil.com发送了一个代表访问者的请求。
为了阻止这个攻击,可以禁止GET请求。evil.com可以在它的页面上放置一个发送POST请求的表单解决这个问题。然后,它可以使用JavaScript代码提交表单,或诱骗访问者提交表单。一个防卫这种攻击的方法是只允许不是由表单使用的内容类型,例如application/json; charset=utf-8。
调用generic handler
为了将开销将到最小,不使用代理,使用jQuery的方法。
- 加载jQuery库。
- 加载JSON插件。可以在http://code.google.com/p/jquery-json/找到这个插件。
- 创建表单数据的JSON对象:
var formdata = { 'title': ..., 'author': ..., 'price': ... };
- 最后,在异步请求中向generic handler发送JSON对象:
$.ajax({ type: "POST", url: "FormHandler.ashx", data: $.toJSON(formdata), contentType: "application/json; charset=utf-8", dataType: "text/plain", success: onSuccess, error: onError }); ... function onSuccess(result) { } function onError(result) { }
如果希望发送请求而不传入任何数据,设置data为空对象”{}”。这样ajax方法在请求中不会设置content-length头,IIS会阻止这个请求。
WCF Data Services和Entity Framework
略
更多资源
Abount ADO.NET Entity Framework:
- The ADO.NET Entity Framework Overview:
http://msdn.microsoft.com/en-us/library/aa697427(VS.80).aspx - Object-relational mapping
http://en.wikipedia.org/wiki/Object-relational_mapping
About WCF Data Services:
- WCF Data Services:
http://msdn.microsoft.com/en-us/library/cc668792.aspx - Open Data Protocol Documentation
http://www.odata.org/developers/protocols - Overview: ADO.NET Data Services
http://msdn.microsoft.com/en-us/library/cc956153.aspx - Using Microsoft ADO.NET Data Services
http://msdn.microsoft.com/en-us/library/cc907912.aspx - Interceptors (WCF Data Services)
http://msdn.microsoft.com/en-us/library/dd744842.aspx