lena和shane,家庭日志,xulavigne,Lena&Shane

如何实现

在C# ASP.Net 中为动态页按需生成静态页或静态文件

2020-03-21 Shane Jhu

访问动态页时(也可以是动态生成的图片,如二维码等),可以自动生成静态资源后输出,下次访问时直接输出静态文件;支持设置过期时间,如果相应静态文件已过期则重新生成。

  1. 只支持GET模式

  2. 可自动判断本地文件是否存在并输出

  3. 支持设置静态文件过期,过期后重新生成

  4. 可按需设置两种重定向方式:Response.Redirect / Server.Transfer

image.png


实现原理

在动态页面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原创,转载请注明出处:查看原文

如果觉得文章还不错,请点个赞吧

2月 27 2025
成年人身上的天真往往很迷人,但若是加上虚荣,就和愚蠢没什么区别。

埃里克·霍弗 (Eric Hoffer 美国作家)