在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原创,转载请注明出处:查看原文
如果觉得文章还不错,请点个赞吧

