在C# ASP.Net 中为动态页按需生成静态页或静态文件
2020-03-21 Shane Jhu
访问动态页时(也可以是动态生成的图片,如二维码等),可以自动生成静态资源后输出,下次访问时直接输出静态文件;支持设置过期时间,如果相应静态文件已过期则重新生成。
只支持GET模式
可自动判断本地文件是否存在并输出
支持设置静态文件过期,过期后重新生成
可按需设置两种重定向方式:Response.Redirect / Server.Transfer
实现原理
在动态页面Page_Load中首先调用此方法做拦截,检查是否存在本地文件,如果文件存在则输出;不存在,则通过WebClient重新访问当前页(强制执行页面的全部代码生成动态结果),将得到的结果资源保存并输出。
这样实现的好处,就是在动态页中直接增加一行调用代码就可以实现效果。
不支持POST,因为习惯性来说POST常常伴随数据库交互,所以这么做没有意义。
核心类
using System; using System.IO; using System.Net; using System.Text; using System.Web.UI; /// <summary> /// StaticSourceBuilder 自动为动态页生成静态资源 /// </summary> public class StaticSourceBuilder { /// <summary> /// 按需创建当前动态页的静态资源并输出 /// </summary> /// <param name="IdKey">用于生成静态文件名的唯一字符串,必须唯一,此参数重复会导致浏览时指向相同的静态文件</param> /// <param name="ext">静态文件扩展名</param> /// <param name="isRedirect">当前动态页面向静态资源的重定向方式,true: 客户端重定向,使用Response.Redirect,URL改变,适用于图片等文件; false: 服务端重定向,使用Server.Transfer,URL不变,适用于页面</param> /// <param name="lifeMS">生命长度,毫秒 0:永不过期 通过静态文件的最后修改时间判断</param> public static void BuildStaticPage(Page p, string IdKey, string ext, bool isRedirect, long lifeMS = 0) { if (!p.IsPostBack) { string QueryName = "__ISBUILDSTATICPAGE"; string isAboutBuild = string.IsNullOrEmpty(p.Request.QueryString[QueryName]) ? "" : p.Request.QueryString[QueryName]; //后台接收页,用于生成并输出静态文件 if (isAboutBuild == "TRUE") { //如果是获取静态页指令,生成静态文件并输出 } else { //1、检测是否存在本地文件 string ClientPath = "/StaticCache/" + ext + "/"; string FileName = ToVid(IdKey).ToString() + "." + ext; string FolderPath = p.Server.MapPath(ClientPath); string FilePath = FolderPath + FileName; if (!Directory.Exists(FolderPath)) { Directory.CreateDirectory(FolderPath); } bool showStaticFile = false; //是否直接输出文件 if (File.Exists(FilePath)) { //如果文件存在且未过期(或无超时需求lifeMS=0),标记直接输出 FileInfo fi = new FileInfo(FilePath); if (lifeMS == 0 || (DateTime.Now - fi.LastWriteTime).TotalMilliseconds < lifeMS) { showStaticFile = true; } } //如果静态文件不存在 或 已过期 if (!showStaticFile) { //生成静态文件 string SourcePageUrl = p.Request.Url + "" + (p.Request.Url.ToString().IndexOf("?") > 0 ? "&" : "?") + QueryName + "=" + "TRUE"; //创建当前动态资源的静态文件 WebClient wc = new WebClient(); wc.Encoding = Encoding.UTF8; if (p.Request.UrlReferrer != null) { wc.Headers["Referer"] = p.Request.UrlReferrer.ToString().Replace("+", "%20"); } byte[] data = wc.DownloadData(SourcePageUrl); var ms = new MemoryStream(data); using (var fs = new FileStream(FilePath, FileMode.Create)) { ms.WriteTo(fs); } ms.Close(); } //2、输出静态文件 if (isRedirect) { p.Response.Redirect(ClientPath + FileName); } else { p.Server.Transfer(ClientPath + FileName, false); } } } } /// <summary> /// 根据字符串生成唯一文件名 /// </summary> /// <param name="str"></param> /// <returns></returns> public static long ToVid(string str) { str = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5"); System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] res = md5.ComputeHash(Encoding.UTF8.GetBytes(str), 0, str.Length); return Math.Abs(BitConverter.ToInt64(res, 0)); } }
调用方式
//放在动态页面Page_Load中 protected void Page_Load(object sender, EventArgs e) { //将调用代码放在此处即可,本例通过URL生成静态资源的唯一文件名 StaticSourceBuilder.BuildStaticPage(this.Page, Request.QueryString.ToString(), "jpg", true, 0); //以下是本例中生成二维码图片的代码,可以忽略 string content = string.IsNullOrEmpty(Request.QueryString["txt"]) ? "http://www.lenashane.com/" : Request.QueryString["txt"]; int size = 200; int border = 10; string htmlColor = string.IsNullOrEmpty(Request.QueryString["color"]) ? ThemeControler.GetColorsRandom().LogThemeColors[0] : (Request.QueryString["color"]); int.TryParse(string.IsNullOrEmpty(Request.QueryString["size"]) ? "200" : Request.QueryString["size"], out size); int.TryParse(string.IsNullOrEmpty(Request.QueryString["border"]) ? "10" : Request.QueryString["border"], out border); System.Drawing.Image image = QRCodePower.CreateQRCode(content, size, border, htmlColor); //将图片输出到页面 System.IO.MemoryStream ms = new System.IO.MemoryStream(); image.Save(ms, System.Drawing.Imaging.ImageFormat.Png); HttpContext.Current.Response.ClearContent(); HttpContext.Current.Response.ContentType = "image/Png"; HttpContext.Current.Response.OutputStream.Write(ms.ToArray(), 0, ms.ToArray().Length); HttpContext.Current.Response.End(); ms.Close(); ms = null; image.Dispose(); image = null; }
本文由lenashane.com原创,转载请注明出处:查看原文
如果觉得文章还不错,请点个赞吧