using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.IO; using System.Text; namespace NetCore.MVC { /// <summary> /// 访问静态页面过滤器 /// </summary> [System.AttributeUsage(AttributeTargets.Method)] public class StaticHtmlAttribute:ActionFilterAttribute { /// <summary> /// 静态路由配置 /// </summary> /// <param name="url">静态路由地址</param> /// <param name="idfield">数据id名称</param> public StaticHtmlAttribute(string url,string idfield="id") { Url = url; idField = idfield; } /// <summary> /// 静态文件路由 /// </summary> public string Url { get; set; } /// <summary> /// 参数标识 /// </summary> public string idField { get; set; } /// <summary> /// 是否清除文件标识 /// </summary> private string RemoveClearKey = "remove"; /// <summary> /// 静态文件根目录 /// </summary> private string StaticFilesRootName { get { return ApplicationEnvironments.Site.BaseDirectory + "html/"; } } public override void OnActionExecuting(ActionExecutingContext context) { string id = context.RouteData.Values.ContainsKey(idField) ? context.RouteData.Values[idField].ToString() : ""; if (string.IsNullOrEmpty(id) && context.HttpContext.Request.Query.ContainsKey(idField)) { id = context.HttpContext.Request.Query[idField]; } string filePath = StaticFilesRootName + string.Format(Url, id); //判断文件是否存在 if (File.Exists(filePath)) { if ( context.HttpContext.Request.Query.ContainsKey(RemoveClearKey)) { RemoveClearKey = context.HttpContext.Request.Query[RemoveClearKey]; if (!string.IsNullOrWhiteSpace(RemoveClearKey)) { File.Delete(filePath); } } else { //若是存在,直接读取文件 using (FileStream fs = File.Open(filePath, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs, Encoding.UTF8)) { //经过contentresult返回文件内容 ContentResult contentresult = new ContentResult(); contentresult.Content = sr.ReadToEnd(); contentresult.ContentType = "text/html"; context.Result = contentresult; } } } } base.OnActionExecuting(context); } public override void OnActionExecuted(ActionExecutedContext context) { CreateHtml(context); base.OnActionExecuted(context); } /// <summary> /// 生成html方法 /// </summary> private void CreateHtml(ActionExecutedContext context) { IActionResult actionResult = context.Result; if (actionResult is ViewResult) { ViewResult viewResult = actionResult as ViewResult; //下面的代码就是执行这个ViewResult,并把结果的html内容放到一个StringBuiler对象中 var services = context.HttpContext.RequestServices; var option = services.GetRequiredService<IOptions<MvcViewOptions>>(); var executor = services.GetRequiredService<IActionResultExecutor<ViewResult>>() as ViewResultExecutor ?? throw new ArgumentNullException("executor"); var result = executor.FindView(context, viewResult); result.EnsureSuccessful(originalLocations: null); var view = result.View; StringBuilder builder = new StringBuilder(); using (var writer = new StringWriter(builder)) { var viewContext = new ViewContext( context, view, viewResult.ViewData, viewResult.TempData, writer, option.Value.HtmlHelperOptions); view.RenderAsync(viewContext).GetAwaiter().GetResult(); //这句必定要调用,不然内容就会是空的 writer.Flush(); } //按照规则生成静态文件名称 string id = context.RouteData.Values.ContainsKey(idField) ? context.RouteData.Values[idField].ToString() : ""; if (string.IsNullOrEmpty(id) && context.HttpContext.Request.Query.ContainsKey(idField)) { id = context.HttpContext.Request.Query[idField]; } string filePath = StaticFilesRootName + string.Format(Url, id); FileInfo info = new FileInfo(filePath); if (!info.Exists) { if (!info.Directory.Exists) { info.Directory.Create(); } } //写入文件 using (FileStream fs = File.Open(filePath, FileMode.Create)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) { sw.Write(builder.ToString()); } } //输出当前的结果 ContentResult contentresult = new ContentResult(); contentresult.Content = builder.ToString(); contentresult.ContentType = "text/html"; context.Result = contentresult; } } } }