Asp.Net与SEO-Viewstate优化终极解决方案
李峻峰 李艳萍 综合 编辑:
dezai 图片来源:网络
viewstate所产生的一堆乱码,严重影响了网站的打开速度和搜索引擎的抓取
第一种解决方案(最快的一种,但是以牺牲asp.net方便性为代价的)西部汽车网
禁用viewstate。可在web.config里配置,或者页面@Page指令里加入 Enableviewstate="false" ,即可防止上面的乱码了。然后页面传值使用form或者cookies,别用session和application他们都是服务器杀手,但这种方式灵活度不高,而且微软自带的控件无法使用了,不如用JSP来做
第二种解决方案:
使用微软的MVC框架,很好用,不过个人感觉开发起来蛮麻烦的,不推荐也不抵触,觉得还不成熟这个东西
第三种解决方案:
使用ajax+web services来搞定,推荐这种方法,真正的页面代码和业务代码分离,很爽,虽然有些烦琐编码的时候,不过感觉很爽。
第四种解决方案:(改写viewSate位置,不对这种方法要每个cs代码都加入重写内容,有点烦。当然可以重写个父类可以解决。但每次都要重写,所以也会增加对服务器CPU开销。好,不多说了,现代码贴上)
要加入using System.Text.RegularExpressions;
private static readonly Regex viewStateRegex =
new Regex("<input type=\"hidden\" name=\"__VIEWSTATE\".*/>", RegexOptions.IgnoreCase); //过滤viewstate html标记的正则表达式
private static readonly Regex endFormRegex =
new Regex(@"</form>", RegexOptions.Multiline | RegexOptions.Compiled); //过滤 </form>标记的正则表达式
//重写HTML,过滤viewstate并输出
protected override void Render(HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string html = stringWriter.ToString();
Match viewStateMatch = viewStateRegex.Match(html);
string viewStateString = viewStateMatch.Captures[0].Value;//找出ViewState的Html标记 目的把viewstate的内容放到页面FORM的最后面加快加载速度和搜索抓录
// viewStateString = "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"\" />"; //仿博客园
html = html.Remove(viewStateMatch.Index, viewStateMatch.Length);//替换掉ViewState的html标记
Match endFormMath = endFormRegex.Match(html, viewStateMatch.Index);
html = html.Insert(endFormMath.Index, viewStateString);//将ViewState的Html标记插入到</form>标记之前
writer.Write(html);
}
这段代码写在你的PAGE基类里,然后看下效果就明白了,把viewstate的内容放在了最后面,这样做两个目的,第一避免VIEWSTATE过大导致页面加载速度过慢,第二避免搜索引擎访问该页面没有找到准确的信息。
第五种解决方案:(重写适配器, 这个方法就比上个方法好在不用增加多余的CPU开销)
该方法使用的ASP.NET控制适配器架构。
控制适配器是一个可以用来控制所产生的HTML控制它适应的类。由于页面类,是一种负责任的渲染视图状态隐藏字段( Page.BeginFormRender调用Page.RenderViewStateFields ),适配器的网页是必要的。然而,视图状态隐藏字段在ASP.NET基础架构中起着关键作用和难以修改相关的HTML 。
一个PageAdapter有一个方法叫做GetStatePersister()返回的对象继承于PageStatePersister 。当加载和保存视图状态的时候调用PageStatePersister。这里有2个类是从PageStatePersister : HiddenFieldPageStatePersister和SessionPageStatePersister继承来的。第一种是默认情况下,存储视图状态中的隐藏字段名为__VIEWSTATE 。第二个存储视图状态在session中。因此,我们可以很容易地创建一个自定义PageStatePersister来控制视图状态加载和保存过程。最大的问题是如何在form标记关闭之前建立隐藏的视图状态,同时以完全透明的解决办法。经过一些尝试我想出了一个解决方案,我很高兴的
具体解决方案(再次感谢这个文章的作者,为asp.net作出的贡献)
(中文:http://www.chinaz.com/Webbiz/Seo/040a20P2009.html (一)
http://www.chinaz.com/Program/.NET/042W39322009.html (二)
英文:http://www.manuelabadia.com/blog/PermaLink,guid,7924eaf8-b406-43af-9444-b816f6dfa246.aspx)
DEMO下载地址:http://www.blog-design.cn/upload/2009/4/SEOViewState.zip
注:但此方法在我实际使用中,发现在如果使用ajax控件的话,如UpdatePanel会出现问题,我三个DropDownList选择后,再全表提交后,取不到DropDownList值。希望能解决这个问题的朋友能告诉我一下,解决方法。谢谢.
第六种解决方案:(ViewState保存在服务器端硬盘上.切记不是用Session,否则如果网站访问量过大的话,可能会极度消耗资源。当然保存在服务器端硬盘上是好是坏,现在的说法也是仁者见仁,智者见智)
(此文来源:http://hi.baidu.com/lwf06017/blo ... 65a5561038c28a.html)
如果你有一个非常酷的页面,页面上很多东西自动地响应用户操作而展现丰富的变化,你的ViewState是很有可能达到200K的。
这里是我将ViewState持久化保持在服务器端的代码,这样ViewState不占用网络带宽,因此其存取只是服务器的磁盘读取时间。并且它很小,可以说是磁盘随便转一圈就能同时读取好多ViewState,因此可以说“不占时间”。为了再“不占磁盘时间”,我还使用了缓存。
一下这段代码可以放在页面中,或者页面的父类中:
using System.IO;
using System.Threading;
protected override object LoadPageStateFromPersistenceMedium()
{
string viewStateID = (string)((Pair)base.LoadPageStateFromPersistenceMedium()).Second;
// var viewStateID = (string)((Pair)base.LoadPageStateFromPersistenceMedium()).Second;
string stateStr = (string)Cache[viewStateID];
if (stateStr == null)
{
string fn = Path.Combine(this.Request.PhysicalApplicationPath, @"App_Data/ViewState/" + viewStateID);
stateStr = File.ReadAllText(fn);
}
return new ObjectStateFormatter().Deserialize(stateStr);
}
protected override void SavePageStateToPersistenceMedium(object state)
{
string value = new ObjectStateFormatter().Serialize(state);
string viewStateID = (DateTime.Now.Ticks + (long)this.GetHashCode()).ToString(); //产生离散的id号码
string fn = this.Server.MapPath(@"~/App_Data/ViewState/" + viewStateID);
//var fn = Path.Combine(this.Request.PhysicalApplicationPath, @"App_Data/ViewState/" + viewStateID);
//ThreadPool.QueueUserWorkItem(obj => File.WriteAllText(fn, value));
File.WriteAllText(fn, value);
Cache.Insert(viewStateID, value);
base.SavePageStateToPersistenceMedium(viewStateID);
}
不使用Session,因为它会“丢失”。ViewState保存在磁盘上,即使服务器重新启动,也不会丢失页面状态。
下面这段可以放在Global.asax中,也可以根本不管:
void Application_Start(object sender, EventArgs e)
{
// 在应用程序启动时运行的代码
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(this.Server.MapPath("~/App_Data/ViewState/"));
if (!dir.Exists)
dir.Create();
else
{
DateTime nt = DateTime.Now.AddHours(-1);
foreach (System.IO.FileInfo f in dir.GetFiles())
{
if (f.CreationTime < nt)
f.Delete();
}
}
}
这可以确保绝对稳定可靠地工作。以后请放心使用ViewState,把交互式页面提高水平才是最重要的,不要纠缠在“ViewState太大”上。实际上,由于页面设计不够酷,交互变化看上去不够丰富,ViewState实在是太小太小了。
如果你使用了它有效提高了复杂交互页面的效率,可以说一下提高了多少?!如果你觉得没用,也可以说一下在什么情况下没用。
来源:CSDN
http://topic.csdn.net/u/20080530 ... 3-b56f080b2161.html
另外,不使用缓存,那么代码就简单一些了,代码变为:
protected override object LoadPageStateFromPersistenceMedium()
{
var viewStateID = (string)((Pair)base.LoadPageStateFromPersistenceMedium()).Second;
var fn = Path.Combine(this.Request.PhysicalApplicationPath, @"App_Data/ViewState/" + viewStateID);
var stateStr = File.ReadAllText(fn);
return new ObjectStateFormatter().Deserialize(stateStr);
}
protected override void SavePageStateToPersistenceMedium(object state)
{
var value = new ObjectStateFormatter().Serialize(state);
var viewStateID = (DateTime.Now.Ticks + (long)this.GetHashCode()).ToString(); //产生离散的id号码
var fn = Path.Combine(this.Request.PhysicalApplicationPath, @"App_Data/ViewState/" + viewStateID);
ThreadPool.QueueUserWorkItem(obj => File.WriteAllText(fn, value));
base.SavePageStateToPersistenceMedium(viewStateID);
}
我认为大家应该知道了缓存的作用,所以我并没有特意去说不过不用缓存,代码如何写。
本文作者:李峻峰 李艳萍 来源:网络
CIO之家 www.ciozj.com 微信公众号:imciow
免责声明:本站转载此文章旨在分享信息,不代表对其内容的完全认同。文章来源已尽可能注明,若涉及版权问题,请及时与我们联系,我们将积极配合处理。同时,我们无法对文章内容的真实性、准确性及完整性进行完全保证,对于因文章内容而产生的任何后果,本账号不承担法律责任。转载仅出于传播目的,读者应自行对内容进行核实与判断。请谨慎参考文章信息,一切责任由读者自行承担。
延伸阅读