Asp.Net与SEO - Viewstate优化终极解决方案

这段时间,老大在看了网站后,发现viewstate所产生的一堆乱码,严重影响了我们网站http://www.xbcar.net 西部汽车网的打开速度和搜索引擎的抓取.就给我下了道铁令,三天内必须解决.这下该轮到我头大了, 

 

例如:
input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="dEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHB1Yl9uYW1lO3B1Yl9uYW1lO3B1Yl9uYW1 lO288Zj47Pj47Ozs7PjtAMDxw" />

 

我立马翻遍了所有的资料,及查遍了百度和Google。以求得到最佳解决方案。但都没有一个完整的解决方案。都写的比较零碎。但黄天不负有心人,最终还是让我找到了几种方案,并加以修改,改进。在此我要感谢这几个方案的提供者。谢谢他们的分享,在解决完我自己的问题后,有感于前几位的分享,故我也不敢独自分享,现在总结七种解决方案如下,以供大家分享,有不对的地方欢迎拍砖。现把ViewState的优化方法总结如下:

 

第一种解决方案(最快的一种,但是以牺牲asp.net方便性为代价的)西部汽车网

 

禁用viewstate。可在web.config里配置,或者页面@Page指令里加入 Enableviewstate="false" ,即可防止上面的乱码了。然后页面传值使用form或者cookies,别用session和application他们都是服务器杀手,但这种方式灵活度不高,而且微软自带的控件无法使用了,不如用JSP来做

 

第二种解决方案:

 

使用微软的MVC框架,很好用,不过个人感觉开发起来蛮麻烦的,不推荐也不抵触,觉得还不成熟这个东西

第三种解决方案:

 

使用ajax+web services来搞定,推荐这种方法,真正的页面代码和业务代码分离,很爽,虽然有些烦琐编码的时候,不过感觉很爽。

 

第四种解决方案:(改写viewSate位置,不对这种方法要每个cs代码都加入重写内容,有点烦。当然可以重写个父类可以解决。但每次都要重写,所以也会增加对服务器开销。好,不多说了,现代码贴上)

 

要加入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 HiddenFieldPageStatePersisterSessionPageStatePersister继承来的。第一种是默认情况下,存储视图状态中的隐藏字段名为__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/blog/item/9815f9526165a5561038c28a.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/22/ef0d36a4-6bd4-4eba-9743-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);
}

我认为大家应该知道了缓存的作用,所以我并没有特意去说不过不用缓存,代码如何写。

即使不用缓存(那么我们也就暂时满足了对缓存忧心忡忡的人,虽然这是不必要的),我们使用服务器端磁盘读的时间来节省服务器通过http从浏览器端读ViewState时间,其结论跟我这个题目要说明的也是一样的。

 

 

 第七种解决方案:(压缩方法,当然此方法在网上一搜一大把了,无就不在这里详述了)

 

总上七总方案。因为我们的网站已成型,又不想太大改,我最后还是选择这第一种和第六种相结合的方法。大家如果有兴趣可以看看我的网站:http://www.xbcar.net 西部汽车网 看看哪些地方还会有ViewState的殘留。好。谢谢。如果大家觉得我这个文章还行,转载时请尽量保留出处http://bbs.xbcar.net/showtopic-3168-1.html#3176 ,也算我没白忙一场,谢谢。.如果还有同志们发现了错误或有更好的解决方案及第,请联系我:QQ:64830979,我将不胜感激.

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值