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