说明:我的环境是vs2010
我们像程序调试的模式一步一步的来看。
1、首先我们来看我的页面
public partial class index : Optimization_WebPage.BasePage {
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { } base.SEO_PageName = "index"; }
2、这里我们在看母版页}
/// <summary> /// 页面基类:这里做了对页面的viewstate优化和Seo操作 /// </summary> public class BasePage : Page { protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.SetOptimization(); this.SetSEOParameters(Seo); } protected override void OnUnload(EventArgs e) { dicCacheKey = null; seo = null; sEO_PageName = null; base.OnUnload(e); } #region viewstate压缩优化 /// <summary> /// 加载优化后的viewState /// 作者:shawn /// TIME :2011.12.19 /// </summary> /// <returns></returns> protected override object LoadPageStateFromPersistenceMedium() { var viewStateID = (string)((Pair)base.LoadPageStateFromPersistenceMedium()).Second; var stateStr = (string)Cache[viewStateID]; if (stateStr == null) { var fn = Path.Combine(this.Request.PhysicalApplicationPath, @"App_Data/ViewState/" + viewStateID); stateStr = File.ReadAllText(fn); } return new ObjectStateFormatter().Deserialize(stateStr); } /// <summary> /// 将viewState优化并进行保存操作 /// 作者: shawn /// Time : 2011.12.19 /// </summary> /// <param name="state"></param> 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); File.WriteAllText(fn, value); Cache.Insert(viewStateID, value); base.SavePageStateToPersistenceMedium(viewStateID); } #endregion #region seo相关操作 /// <summary> /// 页面相关SEO信息设定 /// </summary> /// <param name="title">页面标题.不能为空</param> /// <param name="seo">seo信息类.keyweords和descrption属性不能为空。否则程序异常</param> public virtual void SetSEOParameters(SEOParameters seo) {
//其实下面的各个属性值可以再加上程序动态生成的一些值。例如:*****水果 + seo专员固定写的的seo信息。
//例title.text = title.text + seo.SEO_title。而且还可以增加配置文件来设置规则。好比规则是好比固定的内容在前面。动态的在后面等等 if (Seo != null) { HtmlMeta keywd = new HtmlMeta(), desprtion = new HtmlMeta(), author = new HtmlMeta(), // author copyright = new HtmlMeta(), // copyright date = new HtmlMeta(), // date robots = new HtmlMeta(),// robots equiv = new HtmlMeta(), language = new HtmlMeta(), client_equiv = new HtmlMeta(); HtmlTitle title = new HtmlTitle(); //标题 title.Text = seo.SEO_title; //关键词 keywd.HttpEquiv = "keywords"; keywd.Content = seo.SEO_keyWords; //描述信息 desprtion.HttpEquiv = "description"; desprtion.Content = seo.SEO_desprtion; //编码 equiv.HttpEquiv = "Content-Type"; equiv.Content = seo.SEO_ecoding; //渲染器选择 client_equiv.HttpEquiv = "X-UA-Compatible"; client_equiv.Content = seo.SEO_clientContent; //语言 language.HttpEquiv = "Content-Language"; language.Content = seo.SEO_languagestr; //作者 author.Name = "Author"; author.Content = seo.SEO_authorContent; //版权所有 copyright.Name = "copyright"; copyright.Content = seo.SEO_copyrightContent; //日期 date.Name = "date"; date.Content = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString(); //robots针对搜索引擎 robots.Name = "robots"; robots.Content = seo.SEO_urlRoobts; //将创建的各个SEO标签添加到header this.Header.Controls.AddAt(0, title); this.Header.Controls.AddAt(1, keywd); this.Header.Controls.AddAt(2, desprtion); this.Header.Controls.AddAt(3, equiv); this.Header.Controls.AddAt(4, client_equiv); this.Header.Controls.AddAt(5, language); this.Header.Controls.AddAt(6, author); this.Header.Controls.AddAt(7, copyright); this.Header.Controls.AddAt(8, date); this.Header.Controls.AddAt(9, robots); } } Dictionary<string, SEOParameters> dicCacheKey = null; /// <summary> /// 供外部调用获取已加载到缓存中的seo.xml文件. /// </summary> Dictionary<string, SEOParameters> DicCacheKey { get { if (dicCacheKey == null) { dicCacheKey = Cache["seoCache_Dic"] as Dictionary<string, SEOParameters>; } return dicCacheKey; } set { dicCacheKey = value; } } SEOParameters seo = null; /// <summary> /// seo优化信息实体该值.具体页面指定.如现优化页面为index.那么使用实例为: /// base.Seo = base.DicCacheKey["index"] as SEOParameters; /// </summary> SEOParameters Seo { get { if (seo == null) { if (SEO_PageName != null) { if (DicCacheKey != null) { if (DicCacheKey[SEO_PageName] != null) { seo = DicCacheKey[SEO_PageName] as SEOParameters; } } } } return seo; } set { seo = value; } } string sEO_PageName; /// <summary> /// 对应VirtualPath.xml需要做优化的页面名字.实例:index.aspx或index.html写为index /// </summary> public string SEO_PageName { get { return sEO_PageName; } set { sEO_PageName = value; } } #endregion #region .NET渲染代码以及空白字符优化处理 /// <summary> /// 加载优化 /// </summary> void SetOptimization() { if (!NoOptimizationNuLLStr) { HttpContext.Current.Cache.Insert("OptimizationNuLLStr", true); //其实这里还可以进行封装。慢慢去扩展、吧 } else { HttpContext.Current.Cache.Insert("OptimizationNuLLStr", false);
} if (!NoMovieNetCode) { HttpContext.Current.Cache.Insert("MovieNetCode", true);//其实这里还可以进行封装。慢慢去扩展、吧
} else { HttpContext.Current.Cache.Insert("MovieNetCode", false);//其实这里还可以进行封装。慢慢去扩展、吧
} } bool noOptimizationNuLLStr; /// <summary> /// 指示当前页面是否进行空字符的优化处理.如果不进行相关处理由继承页面将该值设为true /// </summary> public bool NoOptimizationNuLLStr { get { return noOptimizationNuLLStr;} set { noOptimizationNuLLStr = value; } } bool noMovieNetCode; /// <summary> /// 指示当前页面是否进行.NET渲染出的代码移动处理.如果不进行相关处理由继承页面将该值设为true /// </summary> public bool NoMovieNetCode { get { return noMovieNetCode; } set { noMovieNetCode = value; } } #endregion } 很清楚这个页面主要做的事情1、将需要调用的SEO信息的页面名称放入键值对2、加载对应Seo的相关信息。3、viewState压缩保存至服务器端//其实这里还可以进行封装。慢慢去扩展、吧
为什么这么做。很简单。因为程序不知道是哪个页面调用放在缓存中的seo的信息。其实这个basepgae只是取值把值赋予seo的属性在返回给继承它的页面,所以,效率嘛。还是很快的。而且用的是缓存,不存在数据读取等一系列操作。那么问题出来了。我们是什么时候把seo的信息缓存起来的呢?保存在哪呢?seo专员需要修改的时候怎么办呢?
ok,我们接下来就解决这个问题。
我这里做的方式很简单。继承了一个httpmodule。为什么这样做。原因很简单。因为我要保证数据的及时更新。那么每次用户在访问我的时候我只会做一个简单的判断。该seo信息缓存里存在吗?我存放在xml数据里的数据进行了更改吗?如果数据存在缓存中,我这里不会做任何操作。我还验证存放seo的xml文件是否进行了更改,如果更改了,将缓存数据清空,重新加载。加载时候是根据URL重写地址文件来加载。如果没更改,那程序就不会进入相关的加载操作。所以,只有当更改seo文件和程序第一次运行时会加载数据,其他的时候都不会。所以,从效率上可以看出还是不错。ok。不存在的话就不用说了吧。using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Caching; using Optimization_WebPage; using System.Xml; using System.IO; namespace Optimization_WebPage.ViewState { public class SEOSetXMLCache:IHttpModule { public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_UpdateRequestCache); } /// <summary> /// 注册事件.进行事件执行.将 URL地址重写xml数据读入SEOxml。并将SEO xml文档中的数据缓存 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void context_UpdateRequestCache(object sender, EventArgs e) { System.Web.HttpApplication application = (System.Web.HttpApplication)sender; //将 URL地址重写xml数据读入SEOxml this.SetSeoXmlByVirtualPath(application); //并将SEO xml文档中的数据缓存 if (application.Context.Cache["seoCache_Dic"] == null) { this.GetSeoCache(application.Context); } } #region 将SEO xml文档中的数据缓存 /// <summary> /// 对seo相关数据的 xml文档的数据加载到cache缓存 /// </summary> void GetSeoCache(HttpContext Context) { XmlDocument xmlDoc = new XmlDocument(); string tmpPath = HttpContext.Current.Server.MapPath("~/Seo.xml"); if(File.Exists(tmpPath)) { xmlDoc.Load(tmpPath); XmlNodeList xmlNodelist = xmlDoc.SelectSingleNode("Root").ChildNodes; Dictionary<string, SEOParameters> dic_seo = new Dictionary<string, SEOParameters>(); for (int i = 0; i < xmlNodelist.Count; i++) { if (HttpContext.Current.Cache[xmlNodelist.Item(i).Name] == null) { this.SetSEOCache(dic_seo, Context, i, xmlDoc, tmpPath); } } Context.Cache.Insert("seoCache_Dic", dic_seo, new CacheDependency(tmpPath)); } } void SetSEOCache(Dictionary<string, SEOParameters> dic_seo, HttpContext Context, int i, XmlDocument xmlDoc, string tmpPath) { XmlNodeList xmlNodelist = xmlDoc.SelectSingleNode("Root").ChildNodes; dic_seo.Add(xmlNodelist.Item(i).Name, LoadXmlGetSeoParameter(xmlNodelist.Item(i).Name, xmlDoc)); //Context.Cache.Insert(xmlNodelist.Item(i).Name, LoadXmlGetSeoParameter(xmlNodelist.Item(i).Name, xmlDoc), new CacheDependency(tmpPath)); } /// <summary> /// 通过二级节点名获取二级节点下得节点 /// </summary> /// <param name="NodesName"></param> /// <returns></returns> SEOParameters LoadXmlGetSeoParameter(string NodesName, XmlDocument xmlDoc) { SEOParameters seo = new SEOParameters(); XmlNodeList xmlNodeList = xmlDoc.SelectSingleNode("Root").SelectSingleNode(NodesName).ChildNodes; foreach (XmlNode xmlNode in xmlNodeList) { XmlElement mypara = (XmlElement)xmlNode; switch (mypara.Name) { case "title": seo.SEO_title = mypara.InnerText; break; case "discription": seo.SEO_desprtion = mypara.InnerText; break; case "keywords": seo.SEO_keyWords = mypara.InnerText; break; default: seo.SEO_title = ""; seo.SEO_desprtion = ""; seo.SEO_keyWords = ""; break; } } return seo; } #endregion #region 将 URL地址重写xml数据读入SEOxml void SetSeoXmlByVirtualPath(HttpApplication app) { if (app.Context.Cache["IsSetSeoXmlByVirtualPath"] != null) { string Isload = app.Context.Cache["IsSetSeoXmlByVirtualPath"].ToString(); if (Isload == "Yes") { string tmpPathSeo = HttpContext.Current.Server.MapPath("~/Seo.xml"); XmlDocument xmlSeo = null; if (!File.Exists(tmpPathSeo)) { this.AddNodeByXML(xmlSeo, tmpPathSeo); } else { File.Delete(tmpPathSeo); this.AddNodeByXML(xmlSeo, tmpPathSeo); } } } } /// <summary> /// 向SEO xml文档中插入节点 /// </summary> /// <param name="xmlSeo">seoxml文档</param> /// <param name="tmpPathSeo">文档地址</param> void AddNodeByXML(XmlDocument xmlSeo, string tmpPathSeo) { XmlText xmltext; xmlSeo = new XmlDocument(); //加入XML的声明段落 XmlNode xmlnode = xmlSeo.CreateXmlDeclaration("1.0", "utf-8", null); xmlSeo.AppendChild(xmlnode); XmlElement xmlelem = xmlSeo.CreateElement("", "Root", ""); xmltext = xmlSeo.CreateTextNode(""); xmlelem.AppendChild(xmltext); xmlSeo.AppendChild(xmlelem); XmlDocument xmlDoc = new XmlDocument(); string tmpPath = HttpContext.Current.Server.MapPath("~/VirtualPath.xml"); xmlDoc.Load(tmpPath); XmlNodeList xmlNodeList = xmlDoc.SelectSingleNode("RewriterConfig").SelectSingleNode("urls").ChildNodes; for (int i = 0; i < xmlNodeList.Count; i++) { XmlNode node = xmlNodeList[i]; XmlAttribute xmlabuu = null; try { xmlabuu = node.Attributes["virtualUrl"]; } catch (Exception) { continue; } string tmp = xmlabuu.Value; if (!tmp.Contains("(") && !tmp.Contains(")") && !tmp.Contains("\"")) { tmp = tmp.Replace(".html", ""); tmp = tmp.Replace(".htm", ""); tmp = tmp.Replace(".aspx", ""); tmp = tmp.Replace("/", ""); XmlInsertNode(xmlSeo, tmpPathSeo, "Root", tmp, "title", ""); XmlInsertNode(xmlSeo, tmpPathSeo, "Root", tmp, "discription", ""); XmlInsertNode(xmlSeo, tmpPathSeo, "Root", tmp, "keywords", ""); } else { continue; } } xmlSeo.Save(tmpPathSeo); } /// <summary> /// 插入一个节点和此节点的字节点 /// </summary> /// <param name="objXmlDoc">xml文档对象</param> /// <param name="xmlPath">xml路径</param> /// <param name="MailNode">当前节点路径</param> /// <param name="ChildNode">新插入节点</param> /// <param name="Element">插入节点的子节点</param> /// <param name="Content">子节点的内容</param> public static void XmlInsertNode(XmlDocument objXmlDoc, string xmlPath, string MailNode, string ChildNode, string Element, string Content) { XmlNode objRootNode = objXmlDoc.SelectSingleNode(MailNode); XmlNode isNode = objXmlDoc.SelectSingleNode(MailNode).SelectSingleNode(ChildNode); if (isNode == null) { XmlElement objChildNode = objXmlDoc.CreateElement(ChildNode); objRootNode.AppendChild(objChildNode); XmlElement objElement = objXmlDoc.CreateElement(Element); objElement.InnerText = Content; objChildNode.AppendChild(objElement); } else { XmlElement objElement = objXmlDoc.CreateElement(Element); objElement.InnerText = Content; isNode.AppendChild(objElement); } } #endregion } }
那我的xml数据格式是怎么样的呢?我这先贴出来我的url地址重写文件,大家看下
上面我的url地址重写,下面是我根据url重写生成的seo.xml文件<RewriterConfig> <urls> <!--一级栏目--> <add virtualUrl="/index.html" destinationUrl="~/index.aspx"/> <add virtualUrl="/About.html" destinationUrl="~/Abouttyj/AboutTYJ.aspx"/> <add virtualUrl="/News.html" destinationUrl="~/News/News.aspx"/> <add virtualUrl="/Advantage.html" destinationUrl="~/Advantage/Advantage.aspx"/> <add virtualUrl="/Culture.html" destinationUrl="~/Culture/Culture.aspx"/> <add virtualUrl="/Performance.html" destinationUrl="~/Performance/Performance.aspx"/> <add virtualUrl="/Order.html" destinationUrl="~/Order/Order.aspx"/> <add virtualUrl="/Feedback.html" destinationUrl="~/Feedback/Feedback.aspx"/> <!--关于我们--> <add virtualUrl="/About/Honor.html" destinationUrl="~/Abouttyj/Honor.aspx"/> <add virtualUrl="/About/team.html" destinationUrl="~/Abouttyj/Team.aspx"/> <add virtualUrl="/About/Customer.html" destinationUrl="~/Abouttyj/Customer.aspx"/> <add virtualUrl="/About/Recruitment.html" destinationUrl="~/Abouttyj/Recruitment.aspx"/> <add virtualUrl="/About/Contact.html" destinationUrl="~/Abouttyj/Contact.aspx"/> <!--新闻动态--> <add virtualUrl="/Freight.html" destinationUrl="~/News/Freight.aspx"/> <add virtualUrl="/Industry.html" destinationUrl="~/News/Industry.aspx"/> <add virtualUrl="/News/(\d+).html" destinationUrl="~/News/Newsdetail.aspx?name=$1"/> <!--天翼捷优势--> <add virtualUrl="/Fleet.html" destinationUrl="~/Advantage/Fleet.aspx"/> <add virtualUrl="/Warehouse.html" destinationUrl="~/Advantage/Warehouse.aspx"/> <!--天翼捷文化--> <add virtualUrl="/Sentiment.html" destinationUrl="~/Culture/Sentiment.aspx"/> <add virtualUrl="/Train.html" destinationUrl="~/Culture/Train.aspx"/> <!--业绩展示--> <add virtualUrl="/Logistics.html" destinationUrl="~/Performance/Logistics.aspx"/> <add virtualUrl="/Logistics/(\d+).html" destinationUrl="~/Performance/LogisticsDetail.aspx?id=$1"/> <add virtualUrl="/Performance/(\d+).html" destinationUrl="~/Performance/PerformanceDdetail.aspx?id=$1"/> <!--在线订单--> <add virtualUrl="/Order/(\d+).html" destinationUrl="~/Order/OrderDetailed.aspx?id=$1"/> <add virtualUrl="/SeeOrder.html" destinationUrl="~/Order/SeeOrder.aspx"/> <!--留言反馈--> <add virtualUrl="/SeeFeedback.html" destinationUrl="~/Feedback/SeeFeedback.aspx"/> <!--首页搜索--> <add virtualUrl="/Logistics/(\w+)_(\w+)" destinationUrl="~/Performance/Logistics.aspx?city=$1&citys=$2"/> <!--站点地图--> <add virtualUrl="/sitemap.html" destinationUrl="~/siteMap.aspx"/> </urls> </RewriterConfig>
这里是程序第一次运行根据我的源码规则生成的一个只有节点信息没有值得xml文件。那么数据怎么来。呵呵呵,这里就需要问你的seo专员了吧。呵呵呵<?xml version="1.0" encoding="utf-8"?> <Root> <index> <title> </title> <discription> </discription> <keywords> </keywords> </index> <About> <title> </title> <discription> </discription> <keywords> </keywords> </About> <News> <title> </title> <discription> </discription> <keywords> </keywords> </News> <Advantage> <title> </title> <discription> </discription> <keywords> </keywords> </Advantage> <Culture> <title> </title> <discription> </discription> <keywords> </keywords> </Culture> <Performance> <title> </title> <discription> </discription> <keywords> </keywords> </Performance> <Order> <title> </title> <discription> </discription> <keywords> </keywords> </Order> <Feedback> <title> </title> <discription> </discription> <keywords> </keywords> </Feedback> <AboutHonor> <title> </title> <discription> </discription> <keywords> </keywords> </AboutHonor> <Aboutteam> <title> </title> <discription> </discription> <keywords> </keywords> </Aboutteam> <AboutCustomer> <title> </title> <discription> </discription> <keywords> </keywords> </AboutCustomer> <AboutRecruitment> <title> </title> <discription> </discription> <keywords> </keywords> </AboutRecruitment> <AboutContact> <title> </title> <discription> </discription> <keywords> </keywords> </AboutContact> <Freight> <title> </title> <discription> </discription> <keywords> </keywords> </Freight> <Industry> <title> </title> <discription> </discription> <keywords> </keywords> </Industry> <Fleet> <title> </title> <discription> </discription> <keywords> </keywords> </Fleet> <Warehouse> <title> </title> <discription> </discription> <keywords> </keywords> </Warehouse> <Sentiment> <title> </title> <discription> </discription> <keywords> </keywords> </Sentiment> <Train> <title> </title> <discription> </discription> <keywords> </keywords> </Train> <Logistics> <title> </title> <discription> </discription> <keywords> </keywords> </Logistics> <SeeOrder> <title> </title> <discription> </discription> <keywords> </keywords> </SeeOrder> <SeeFeedback> <title> </title> <discription> </discription> <keywords> </keywords> </SeeFeedback> <sitemap> <title> </title> <discription> </discription> <keywords> </keywords> </sitemap> </Root>
下面是我的SEOparamertes 类:
下面代码是对viewstate的移动和是否需要对空字符进行出来。就是对渲染出来的html结果排成类似于百度、google的源码那里。最大化限度减少文件的空白字符,增加传输速度。using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Optimization_WebPage { public class SEOParameters { public SEOParameters() { } public SEOParameters(string _title,string _desprtion,string _keyWords,string _ecoding, string _authorContent, string _copyright, string _language, string _clientContent, string _urlRoobts) { _SEO_title = _title; _SEO_desprtion = _desprtion; _SEO_keyWords = _keyWords; _SEO_authorContent = _authorContent; _SEO_clientContent = _clientContent; _SEO_copyrightContent = _copyright; _SEO_urlRoobts = _urlRoobts; _SEO_languagestr = _language; _SEO_ecoding = _ecoding; } public SEOParameters(string _title,string _desprtion,string _keyWords) { _SEO_title = _title; _SEO_desprtion = _desprtion; _SEO_keyWords = _keyWords; } string _SEO_title = ""; /// <summary> /// 标题信息.该值不能为空.否则程序异常.且最多只能接受80个字符 /// </summary> public string SEO_title { get { return _SEO_title.Length > 80 ? _SEO_title.Substring(0, 79) : _SEO_title; } set { _SEO_title = value; } } string _SEO_desprtion = ""; /// <summary> /// 页面描述信息.该值不能为空.否则程序异常.且最多只能接受200个字符 /// </summary> public string SEO_desprtion { get { return _SEO_desprtion.Length > 200 ? _SEO_desprtion.Substring(0, 199) : _SEO_desprtion; } set { _SEO_desprtion = value; } } string _SEO_keyWords = ""; /// <summary> /// 页面关键词.该值不能为空.否则程序异常.且最多只能接受100个字符 /// </summary> public string SEO_keyWords { get { return _SEO_keyWords.Length > 100 ? _SEO_keyWords.Substring(0, 99) : _SEO_keyWords; } set { _SEO_keyWords = value; } } string _SEO_ecoding = ""; /// <summary> /// 编码方式.如果值为"".系统默认会设置值为:text/html;charset=utf-8 /// </summary> public string SEO_ecoding { get { return _SEO_ecoding == "" ? "text/html;charset=utf-8" : _SEO_ecoding; } set { _SEO_ecoding = value;} } string _SEO_authorContent = ""; /// <summary> /// 著作者:如果值为""。系统默认会设置值为:www.ay56.cn /// </summary> public string SEO_authorContent { get { return _SEO_authorContent == "" ? "http://www.ay56.cn" : _SEO_authorContent; } set { _SEO_authorContent = value; } } string _SEO_copyrightContent = ""; /// <summary> /// 版权所有.如果值为""。系统默认会设置值为:www.ay56.cn /// </summary> public string SEO_copyrightContent { get { return _SEO_copyrightContent == "" ? "http://www.ay56.cn" : _SEO_copyrightContent; } set { _SEO_copyrightContent = value;} } string _SEO_languagestr = ""; /// <summary> /// 网页语言:如果值为"",系统默认会设置值为:utf-8 /// </summary> public string SEO_languagestr { get { return _SEO_languagestr == "" ? "utf-8" : _SEO_languagestr; } set { _SEO_languagestr = value; } } string _SEO_clientContent = ""; /// <summary> /// 客户端HTML文件渲染器.如果值为"",系统默认会设置值为:IE=EmulateIE7 /// </summary> public string SEO_clientContent { get { return _SEO_clientContent == "" ? "IE=EmulateIE7" : _SEO_clientContent; } set { _SEO_clientContent = value; } } string _SEO_urlRoobts = ""; /// <summary> /// 搜苏引擎索引目录地址:如果存在该文件,给于文件路径.如果值为"",系统默认会设置值为:"all" /// </summary> public string SEO_urlRoobts { get { return _SEO_urlRoobts == "" ? "all" : _SEO_urlRoobts; } set { _SEO_urlRoobts = value; } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text.RegularExpressions; namespace Optimization_WebPage.ViewState { /// <summary> /// 移动隐藏字段 __VIEWSTATE 到 /Form 之前. /// 作者:shawn /// </summary> public class MoveViewStateFilter : System.IO.MemoryStream { System.IO.Stream _filter; bool _filtered = false; /// <param name="filter">A reference to the downstream HttpResponse.Filter.</param> public MoveViewStateFilter( System.IO.Stream filter ) { _filter = filter; } /// <summary>Closes this filter stream.</summary> /// <remarks> /// The contents of this filter are written to the downstream filter after the hidden /// __VIEWSTATE form field is moved. /// </remarks> public override void Close() { //获取针对该页面是否进行空字符优化处理操作 bool OptimizationNuLLStr = HttpContext.Current.Cache["OptimizationNuLLStr"] != null ? (bool)HttpContext.Current.Cache["OptimizationNuLLStr"] : false; //获取针对该页面是否进行.NET代码移动操作 bool MovieNetCode = HttpContext.Current.Cache["MovieNetCode"] != null ? (bool)HttpContext.Current.Cache["MovieNetCode"] : false; if (_filtered) { if (this.Length > 0) { byte[] bytes = null; ; string content = System.Text.Encoding.UTF8.GetString(this.ToArray()); string tmp = "http://" + HttpContext.Current.Request.Url.Host + "/"; if (MovieNetCode) //是否进行移动处理 { if (content.Contains("<div class=\"aspNetHidden\"")) { content = this.STRINGMOVE(content, "<div class=\"aspNetHidden\"", "</div>", "</form>"); } else { content = this.STRINGMOVE(content, "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\"", "/>", "</form>"); content = this.STRINGMOVE(content, "<input type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\"", "/>", "</form>"); } content = this.STRINGMOVE(content, "<script src=\"/WebResource.axd?", "</script>", "</form>"); if (content.Contains("<script src=\"/ScriptResource.axd?")) { for (int i = 0; i < 3; i++) { content = this.STRINGMOVE(content, "<script src=\"/ScriptResource.axd?", "</script>", "</form>"); } } if (content.Contains("<script type=\"text/javascript\">\r\n//<![CDATA[")) { for (int i = 0; i < 3; i++) { content = this.STRINGMOVE(content, "<script type=\"text/javascript\">\r\n//<![CDATA[", "//]]>\r\n</script>", "</form>"); } } content = this.STRINGMOVE(content, "<script type=\'text/javascript\'>new Sys.WebForms.Menu", "</script>", "</form>"); } if (OptimizationNuLLStr) //是否进行空字符优化 { 多余字符替换为"" System.Text.RegularExpressions.Regex regex = new Regex(@" ", System.Text.RegularExpressions.RegexOptions.IgnoreCase); System.Text.RegularExpressions.Regex regextwo = new Regex(@"\r\n", System.Text.RegularExpressions.RegexOptions.IgnoreCase); System.Text.RegularExpressions.Regex regexthree = new Regex(@"\r\n\t", System.Text.RegularExpressions.RegexOptions.IgnoreCase); content = regexthree.Replace(content, ""); content = regextwo.Replace(content, ""); content = regex.Replace(content, ""); } bytes = System.Text.Encoding.UTF8.GetBytes(content); _filter.Write(bytes, 0, bytes.Length); tmp = null; content = null; } _filter.Close(); } base.Close(); } /// <summary> /// 移动字符串 /// </summary> /// <param name="content">渲染出来的内容</param> /// <param name="MoveString_start">要移动字符串的开始字符</param> /// <param name="MoveString_End">要移动字符串的结束字符</param> /// <param name="Insert_string">需要在哪个字符前插入你需要移动的字</param> /// <param name="tmpCount">要移动字符串的结束字符串的长度</param> string STRINGMOVE(string content, string MoveString_start, string MoveString_End, string Insert_string) { int MoveStringIndex_start = content.IndexOf(MoveString_start); if (MoveStringIndex_start > 0) { int MoveStringIndex_End = content.IndexOf(MoveString_End, MoveStringIndex_start) + MoveString_End.Length; string MoviString = content.Substring(MoveStringIndex_start, MoveStringIndex_End - MoveStringIndex_start) + "\n"; content = content.Remove(MoveStringIndex_start, MoveStringIndex_End - MoveStringIndex_start); int Insert_stringIndex = content.IndexOf(Insert_string); if (Insert_stringIndex >= 0) { content = content.Insert(Insert_stringIndex, MoviString); MoviString = null; return content; } } return content; } public override void Write( byte[] buffer, int offset, int count ) { if ( ( System.Web.HttpContext.Current != null ) && ( "text/html" == System.Web.HttpContext.Current.Response.ContentType ) ) { base.Write( buffer, offset, count ); _filtered = true; } else { _filter.Write( buffer, offset, count ); _filtered = false; } } /// <summary> /// 便利渲染后的字符串。对其中的a标签和link标签的href进行重赋值 /// </summary> /// 作者:shawn /// <param name="content">渲染出来的结果</param> /// <param name="tmp">标头字符串</param> string insertHostName(string content,string tmp) { //该正则需优化 //string reg = @"<a[^>]*href=(""(?<href>[^""]*)""|'(?<href>[^']*)'|(?<href>[^\s>]*))[^>]*>(?<text>[\s\S]*?)</a>"; //逍遥 //string reg = @"<\s*a\b(?![^<>]*?(javascript|__doPostBack))[^<>]+?href=(['""]?)(?<url>[^*#<>()]*?)\2[^>]*>"; //string reg = @"(?i)<(a|link)\s[^>]*?href=(['""]?)(?!javascript|__doPostBack|alert)(?<url>[^'""\s*#<>()]+)[^>]*>"; //string reg = @"(?i)<a\s[^>]*?href=(['""]?)(?!javascript|__doPostBack)(?<url>[^'""\s*#<>]+)[^>]*>"; string reg = @"(?i)<(?:img\s[^>]*?(?<url>src=(['""]?)[^'""\s*#<>()]+\1)|(?:a|link)\s[^>]*?(?<url>href=(['""]?)(?!javascript|__doPostBack|alert)[^'""\s*#<>()]+\2))[^>]*>"; MatchCollection mc1 = Regex.Matches(content, reg, RegexOptions.IgnoreCase | RegexOptions.Compiled); for (int i = 0; i < mc1.Count; i++) { string href_url = mc1[i].Groups["url"].Value;// 这里取到了href属性值 //拼接后的url1 //string href = "href=\"" + href_url + "\""; //string hreftwo = "href=" + href_url; if (!href_url.Contains(tmp) && !href_url.Contains("javascript") && !href_url.Contains("#") && !href_url.Contains("(") && !href_url.Contains("__doPostBack") && !href_url.Contains("*") && !href_url.Contains("<") && href_url != "" && !href_url.Contains(")") && !href_url.Contains(">") && !href_url.Contains("http://")) { content = this.Movie(href_url, content, tmp); } } return content; } /// <summary> /// 删除插入替换法 /// </summary> /// 作者:shawn /// <param name="href">链接</param> /// <param name="content">渲染的结果</param> /// <param name="tmp">标头</param> /// <param name="tmpInt">截取的index</param> /// <returns></returns> string Movie(string href,string content,string tmp) { int StarIndex = content.IndexOf(href); if (StarIndex != -1) { int EndIndex = content.IndexOf(">", StarIndex); href = href.Replace("href",""); href = href.Replace("=",""); href = href.Replace("\"", ""); if (href.IndexOf("../") == 0) { href = href.Remove(0, 3); } else if (href.IndexOf("~/") == 0) { href = href.Remove(0, 2); } else if (href.IndexOf("/") == 0 || href.IndexOf("~") == 0) { href = href.Remove(0, 1); } content = content.Remove(StarIndex, EndIndex - StarIndex); content = content.Insert(StarIndex, "href=\"" + tmp + href + "\""); return content; } return content; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; namespace Optimization_WebPage.ViewState { /// <summary> /// 注册移动事件.开始进行viewstate移动 /// 作者:shawn /// </summary> public class MoveViewStateModule : System.Web.IHttpModule { public MoveViewStateModule() { } void System.Web.IHttpModule.Dispose() { } void System.Web.IHttpModule.Init( System.Web.HttpApplication context ) { context.BeginRequest += new EventHandler( this.BeginRequestHandler ); } void BeginRequestHandler( object sender, EventArgs e ) { System.Web.HttpApplication application = ( System.Web.HttpApplication )sender; application.Response.Filter = new MoveViewStateFilter( application.Response.Filter ); } } }
有朋友问我你为什么不写在Application_Start事件来加载数据。还是那个回答,数据的及时性。我的缓存数据是根据xml做的缓存、如果xml一旦修改。数据会重新加载。//如需使用BasePage.请再web应用的Global文件中对应的事件替换一下代码并导入命名空间using System.IO; protected void Application_Start(object sender, EventArgs e) { DirectoryInfo dir = new DirectoryInfo(this.Server.MapPath("~/App_Data/ViewState/")); if (!dir.Exists) dir.Create(); else { DateTime nt = DateTime.Now.AddHours(-1); foreach (FileInfo f in dir.GetFiles()) { if (f.CreationTime < nt) f.Delete(); } } }
别忘了、这个是配合url地址重写用的。所以我们还需要做一件事情:
using System; using System.Web; using System.Configuration; using System.Xml.Serialization; using System.Web.Caching; namespace Module.config { [Serializable()] [XmlRoot("RewriterConfig")] public class UrlConfiguration { public UrlConfiguration() { } /// <summary> /// 返回配置文件中的RewriterConfig配置节.提示信息.该数据缓存依赖于文件 /// </summary> /// <returns></returns> public static UrlConfigurationSection GetConfig() { if (HttpContext.Current.Cache["RewriterConfig"] == null) { HttpContext.Current.Cache.Insert("RewriterConfig", ConfigurationManager.GetSection("RewriterConfig"), new CacheDependency(HttpContext.Current.Server.MapPath("~/VirtualPath.xml"))); HttpContext.Current.Cache.Insert("IsSetSeoXmlByVirtualPath", "Yes"); } else { if (HttpContext.Current.Cache["IsSetSeoXmlByVirtualPath"] != null) { HttpContext.Current.Cache["IsSetSeoXmlByVirtualPath"] = "No"; } else { HttpContext.Current.Cache.Insert("IsSetSeoXmlByVirtualPath", "No"); } } return (UrlConfigurationSection)HttpContext.Current.Cache["RewriterConfig"]; } } }
至此。已经写完了。其实这个东西很早了,已经很多站在使用。最后你还可以开发一个管理的一个页面对xml进行管理。很方面。呵呵呵。很多还不完善,需要大家一起来完善。