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; } } } }