mirror of
https://github.com/dotnetcore/Util.git
synced 2026-10-28 02:46:37 +08:00
实现 Razor生成NG Html文件
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Util.Helpers;
|
||||
using Util.Webs.Controllers;
|
||||
using Util.Webs.Razors;
|
||||
|
||||
namespace Util.Samples.Webs.Apis.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化Razor控制器
|
||||
/// </summary>
|
||||
public class InitRazorController : WebApiControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Razor静态Html生成器
|
||||
/// </summary>
|
||||
public IRazorHtmlGenerator RazorHtmlGenerator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个<see cref="InitRazorController"/>类型的实例
|
||||
/// </summary>
|
||||
/// <param name="razorHtmlGenerator"></param>
|
||||
public InitRazorController(IRazorHtmlGenerator razorHtmlGenerator)
|
||||
{
|
||||
RazorHtmlGenerator = razorHtmlGenerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化路由
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Route("/api/init")]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Init()
|
||||
{
|
||||
await RazorHtmlGenerator.Generate();
|
||||
return new JsonResult("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,9 @@ namespace Util.Samples.Webs {
|
||||
options.IncludeXmlComments( Path.Combine( AppContext.BaseDirectory, "Util.Samples.Webs.xml" ) );
|
||||
} );
|
||||
|
||||
// 添加Razor静态Html生成器
|
||||
services.AddRazorHtml();
|
||||
|
||||
//添加Util基础设施服务
|
||||
return services.AddUtil();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Util.Webs.Razors;
|
||||
|
||||
namespace Util.Webs.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务扩展
|
||||
/// </summary>
|
||||
public static partial class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册Razor静态Html生成器
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddRazorHtml(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IRouteAnalyzer, RouteAnalyzer>();
|
||||
services.AddScoped<IRazorHtmlGenerator, DefaultRazorHtmlGenerator>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Util.Helpers;
|
||||
using Util.Logs;
|
||||
using Util.Logs.Extensions;
|
||||
|
||||
namespace Util.Webs.Razors
|
||||
{
|
||||
/// <summary>
|
||||
/// Razor静态Html生成器
|
||||
/// </summary>
|
||||
public class DefaultRazorHtmlGenerator:IRazorHtmlGenerator
|
||||
{
|
||||
private readonly IRouteAnalyzer _routeAnalyzer;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个<see cref="DefaultRazorHtmlGenerator"/>类型的实例
|
||||
/// </summary>
|
||||
/// <param name="routeAnalyzer">路由分析器</param>
|
||||
public DefaultRazorHtmlGenerator(IRouteAnalyzer routeAnalyzer)
|
||||
{
|
||||
_routeAnalyzer = routeAnalyzer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成Html文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task Generate()
|
||||
{
|
||||
foreach (var routeInformation in _routeAnalyzer.GetAllRouteInformations())
|
||||
{
|
||||
// 跳过API的处理
|
||||
if (routeInformation.Path.StartsWith("/api"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
await WriteViewToFileAsync(routeInformation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渲染视图为字符串
|
||||
/// </summary>
|
||||
/// <param name="info">路由信息</param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> RenderToStringAsync(RouteInformation info)
|
||||
{
|
||||
var razorViewEngine = Ioc.Create<IRazorViewEngine>();
|
||||
var tempDataProvider = Ioc.Create<ITempDataProvider>();
|
||||
var serviceProvider = Ioc.Create<IServiceProvider>();
|
||||
|
||||
var routeData = new RouteData();
|
||||
if (!info.AreaName.IsEmpty())
|
||||
{
|
||||
routeData.Values.Add("area", info.AreaName);
|
||||
}
|
||||
|
||||
if (!info.ControllerName.IsEmpty())
|
||||
{
|
||||
routeData.Values.Add("controller", info.ControllerName);
|
||||
}
|
||||
|
||||
if (!info.ActionName.IsEmpty())
|
||||
{
|
||||
routeData.Values.Add("action", info.ActionName);
|
||||
}
|
||||
|
||||
var httpContext = new DefaultHttpContext { RequestServices = serviceProvider };
|
||||
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
|
||||
|
||||
var viewResult = razorViewEngine.FindView(actionContext, info.ActionName, true);
|
||||
if (!viewResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException($"找不到视图模板 {info.ActionName}");
|
||||
}
|
||||
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
|
||||
var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, tempDataProvider), stringWriter, new HtmlHelperOptions());
|
||||
await viewResult.View.RenderAsync(viewContext);
|
||||
return stringWriter.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将视图写入文件
|
||||
/// </summary>
|
||||
/// <param name="info">路由信息</param>
|
||||
/// <returns></returns>
|
||||
public async Task WriteViewToFileAsync(RouteInformation info)
|
||||
{
|
||||
try
|
||||
{
|
||||
var html = await RenderToStringAsync(info);
|
||||
if (string.IsNullOrWhiteSpace(html))
|
||||
return;
|
||||
|
||||
var path = Util.Helpers.Common.GetPhysicalPath(string.IsNullOrWhiteSpace(info.FilePath) ? GetPath(info) : info.FilePath);
|
||||
var directory = System.IO.Path.GetDirectoryName(path);
|
||||
if (string.IsNullOrWhiteSpace(directory))
|
||||
return;
|
||||
if (Directory.Exists(directory) == false)
|
||||
Directory.CreateDirectory(directory);
|
||||
File.WriteAllText(path, html);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Log(Log.GetLog().Caption("生成html静态文件失败"));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string GetPath(RouteInformation info)
|
||||
{
|
||||
var area = info.AreaName.SafeString();
|
||||
var controller = info.ControllerName.SafeString();
|
||||
var action = info.ActionName.SafeString();
|
||||
var path = info.TemplatePath.Replace("{area}", area).Replace("{controller}", controller).Replace("{action}", action);
|
||||
return path.ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Util.Webs.Razors
|
||||
{
|
||||
/// <summary>
|
||||
/// Razor Html生成器
|
||||
/// </summary>
|
||||
public interface IRazorHtmlGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成Html文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task Generate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Util.Webs.Razors
|
||||
{
|
||||
/// <summary>
|
||||
/// 路由分析器
|
||||
/// </summary>
|
||||
public interface IRouteAnalyzer
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有路由信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerable<RouteInformation> GetAllRouteInformations();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Util.Webs.Filters;
|
||||
|
||||
namespace Util.Webs.Razors
|
||||
{
|
||||
/// <summary>
|
||||
/// 路由分析器
|
||||
/// </summary>
|
||||
public class RouteAnalyzer:IRouteAnalyzer
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作描述集合提供程序
|
||||
/// </summary>
|
||||
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个<see cref="RouteAnalyzer"/>类型的实例
|
||||
/// </summary>
|
||||
/// <param name="actionDescriptorCollectionProvider">操作描述集合提供程序</param>
|
||||
public RouteAnalyzer(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
|
||||
{
|
||||
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有路由信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<RouteInformation> GetAllRouteInformations()
|
||||
{
|
||||
List<RouteInformation> list=new List<RouteInformation>();
|
||||
|
||||
var actionDescriptors = this._actionDescriptorCollectionProvider.ActionDescriptors.Items;
|
||||
foreach (var actionDescriptor in actionDescriptors)
|
||||
{
|
||||
RouteInformation info=new RouteInformation();
|
||||
|
||||
if (actionDescriptor.RouteValues.ContainsKey("area"))
|
||||
{
|
||||
info.AreaName = actionDescriptor.RouteValues["area"];
|
||||
}
|
||||
|
||||
// Razor页面路径以及调用
|
||||
if (actionDescriptor is PageActionDescriptor pageActionDescriptor)
|
||||
{
|
||||
info.Path = pageActionDescriptor.ViewEnginePath;
|
||||
info.Invocation = pageActionDescriptor.RelativePath;
|
||||
}
|
||||
|
||||
// 路由属性路径
|
||||
if (actionDescriptor.AttributeRouteInfo != null)
|
||||
{
|
||||
info.Path = $"/{actionDescriptor.AttributeRouteInfo.Template}";
|
||||
}
|
||||
|
||||
// Controller/Action 的路径以及调用
|
||||
if (actionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
||||
{
|
||||
if (info.Path.IsEmpty())
|
||||
{
|
||||
info.Path =
|
||||
$"/{controllerActionDescriptor.ControllerName}/{controllerActionDescriptor.ActionName}";
|
||||
}
|
||||
|
||||
var controllerHtmlAttribute = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttribute<HtmlAttribute>();
|
||||
|
||||
if (controllerHtmlAttribute != null)
|
||||
{
|
||||
info.FilePath = controllerHtmlAttribute.Path;
|
||||
info.TemplatePath = controllerHtmlAttribute.Template;
|
||||
}
|
||||
|
||||
var htmlAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttribute<HtmlAttribute>();
|
||||
|
||||
if (htmlAttribute != null)
|
||||
{
|
||||
info.FilePath = htmlAttribute.Path;
|
||||
info.TemplatePath = htmlAttribute.Template;
|
||||
}
|
||||
|
||||
info.ControllerName = controllerActionDescriptor.ControllerName;
|
||||
info.ActionName = controllerActionDescriptor.ActionName;
|
||||
info.Invocation = $"{controllerActionDescriptor.ControllerName}Controller.{controllerActionDescriptor.ActionName}";
|
||||
}
|
||||
|
||||
info.Invocation += $"({actionDescriptor.DisplayName})";
|
||||
|
||||
list.Add(info);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Util.Webs.Razors
|
||||
{
|
||||
/// <summary>
|
||||
/// 路由信息
|
||||
/// </summary>
|
||||
public class RouteInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// 区域名称
|
||||
/// </summary>
|
||||
public string AreaName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 控制器名称
|
||||
/// </summary>
|
||||
public string ControllerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作名称
|
||||
/// </summary>
|
||||
public string ActionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Razor页面路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 调用方法
|
||||
/// </summary>
|
||||
public string Invocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板路径
|
||||
/// </summary>
|
||||
public string TemplatePath { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user