Razor页面静态化

2018/05/09 200

class RazorViewCacheAttribute : ActionFilterAttribute
{
    /// <summary>
    /// Store the view result by the Action as a static file
    /// </summary>
    /// <param name="fileName">cache file name. likes 'a.html', 'dir/a.html', 'a_{id}.html' {id} is a route data</param>
    /// <param name="viewName"></param>
    public RazorViewCacheAttribute(string fileName, string viewName = null)
    {
        FileName = fileName.TrimStart('/');
        this.viewName = viewName;
    }

    readonly Regex reg = new Regex(@"{(\w+)}");

    string FileName { get; }
    readonly string viewName;

    bool IsHandle { get; set; }

    private string ParseFileName(RouteData routeData)
        {
            var mathches = reg.Matches(FileName);
            string resultFileName = FileName;
            foreach (Match item in mathches)
            {
                if (routeData.Values.ContainsKey(item.Groups[1].Value))
                {
                    resultFileName = resultFileName.Replace(item.Groups[0].Value, routeData.Values[item.Groups[1].Value].ToString());
                }
                else
                {
                    resultFileName = resultFileName.Replace(item.Groups[0].Value, "");
                }
            }
            return resultFileName;
        }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string path = filterContext.HttpContext.Server.MapPath("~/wwwroot/static/" + ParseFileName(filterContext.RouteData));
        if (File.Exists(path))
        {
            filterContext.Result = new ContentResult
            {
                Content = File.ReadAllText(path)
            };
            IsHandle = true;
        }
        else
        {
            base.OnActionExecuting(filterContext);
        }
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (!IsHandle)
        {
            if (filterContext.Result is ViewResultBase viewResult)
            {
                using (var sw = new StringWriter())
                {
                    string viewName = viewResult.ViewName;
                    if (string.IsNullOrEmpty(viewResult.ViewName))
                    {
                        viewName = filterContext.RouteData.Values["action"].ToString();
                    }
                    var viewEngineResult = ViewEngines.Engines.FindPartialView(filterContext.Controller.ControllerContext, viewName);
                    var viewContext = new ViewContext(filterContext.Controller.ControllerContext, viewEngineResult.View, viewResult.ViewData, viewResult.TempData, sw);
                    viewEngineResult.View.Render(viewContext, sw);
                    viewEngineResult.ViewEngine.ReleaseView(filterContext.Controller.ControllerContext, viewEngineResult.View);
                    string html = sw.GetStringBuilder().ToString();
                    string path = filterContext.HttpContext.Server.MapPath("~/wwwroot/static/" + ParseFileName(filterContext.RouteData));
                    string dirPath = Path.GetDirectoryName(path);
                    if (!Directory.Exists(dirPath))
                    {
                        Directory.CreateDirectory(dirPath);
                    }
                    File.WriteAllText(path, html);
                }
            }
            else
            {
                throw new InvalidOperationException("The result of the action must be 'ViewResultBase', please try 'return View()'");
            }
        }
    }
}
评论