汝州网站制作,软件开发工作岗位,网络公司推广方案,网站建设服务器租赁一、前言最近做项目的时候#xff0c;使用Util进行开发#xff0c;使用Razor写前端页面。初次使用感觉还是不大习惯#xff0c;之前都是前后端分离的方式开发的#xff0c;但是使用Util封装后的Angular后#xff0c;感觉开发效率还是杠杠滴。二、问题在发布代码的时候使用Util进行开发使用Razor写前端页面。初次使用感觉还是不大习惯之前都是前后端分离的方式开发的但是使用Util封装后的Angular后感觉开发效率还是杠杠滴。二、问题在发布代码的时候Webpack打包异常提示是缺少了某些Html文件我看了下相应的目录发现目录缺少了部分Html文件然后就问了何镇汐大大给出的解决方案是每个页面都需要访问一下才能生成相应的Html静态文件。这时候就产生了疑虑是否有一种方式能获取所有路由然后只需访问一次即可生成所有的Html页面。三、解决方案3.1 每次访问生成Html解决方案思路继承ActionFilterAttribute特性重写执行方法访问的时候判断访问的Result是否ViewResult如果是方可生成Html从RazorViewEngine中查找到View后进行渲染/// summary/// 生成Html静态文件/// /summarypublic class HtmlAttribute : ActionFilterAttribute { /// summary /// 生成路径相对根路径范例/Typings/app/app.component.html /// /summary public string Path { get; set; } /// summary /// 路径模板范例Typings/app/{area}/{controller}/{controller}-{action}.component.html /// /summary public string Template { get; set; } /// summary /// 执行生成 /// /summary public override async Task OnResultExecutionAsync( ResultExecutingContext context, ResultExecutionDelegate next ) { await WriteViewToFileAsync( context ); await base.OnResultExecutionAsync( context, next ); } /// summary /// 将视图写入html文件 /// /summary private async Task WriteViewToFileAsync( ResultExecutingContext context ) { try { var html await RenderToStringAsync( context ); if( string.IsNullOrWhiteSpace( html ) ) return; var path Util.Helpers.Common.GetPhysicalPath( string.IsNullOrWhiteSpace( Path ) ? GetPath( context ) : Path ); 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静态文件失败 ) ); } } /// summary /// 渲染视图 /// /summary protected async Taskstring RenderToStringAsync( ResultExecutingContext context ) { string viewName ; object model null; if( context.Result is ViewResult result ) { viewName result.ViewName; viewName string.IsNullOrWhiteSpace( viewName ) ? context.RouteData.Values[action].SafeString() : viewName; model result.Model; } var razorViewEngine Ioc.CreateIRazorViewEngine(); var tempDataProvider Ioc.CreateITempDataProvider(); var serviceProvider Ioc.CreateIServiceProvider(); var httpContext new DefaultHttpContext { RequestServices serviceProvider }; var actionContext new ActionContext( httpContext, context.RouteData, new ActionDescriptor() ); using( var stringWriter new StringWriter() ) { var viewResult razorViewEngine.FindView( actionContext, viewName, true ); if( viewResult.View null ) throw new ArgumentNullException( $未找到视图 {viewName} ); var viewDictionary new ViewDataDictionary( new EmptyModelMetadataProvider(), new ModelStateDictionary() ) { Model model }; 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 /// 获取Html默认生成路径 /// /summary protected virtual string GetPath( ResultExecutingContext context ) { var area context.RouteData.Values[area].SafeString(); var controller context.RouteData.Values[controller].SafeString(); var action context.RouteData.Values[action].SafeString(); var path Template.Replace( {area}, area ).Replace( {controller}, controller ).Replace( {action}, action ); return path.ToLower(); }}3.2 一次访问生成所有Html解决方案思路获取所有已注册的路由获取使用RazorHtml自定义特性的路由忽略Api接口的路由构建RouteData信息用于在RazorViewEngine中查找到相应的视图构建ViewContext用于渲染出Html字符串将渲染得到的Html字符串写入文件获取所有注册的路由此处是比较重要的其他地方也可以用到。/// summary/// 获取所有路由信息/// /summary/// returns/returnspublic IEnumerableRouteInformation GetAllRouteInformations(){ ListRouteInformation list new ListRouteInformation(); 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.GetCustomAttributeRazorHtmlAttribute(); if (controllerHtmlAttribute ! null) { info.FilePath controllerHtmlAttribute.Path; info.TemplatePath controllerHtmlAttribute.Template; } var htmlAttribute controllerActionDescriptor.MethodInfo.GetCustomAttributeRazorHtmlAttribute(); 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;}生成Html静态文件/// summary/// 生成Html文件/// /summary/// returns/returnspublic async Task Generate(){ foreach (var routeInformation in _routeAnalyzer.GetAllRouteInformations()) { // 跳过API的处理 if (routeInformation.Path.StartsWith(/api)) { continue; } await WriteViewToFileAsync(routeInformation); }}/// summary/// 渲染视图为字符串/// /summary/// param nameinfo路由信息/param/// returns/returnspublic async Taskstring RenderToStringAsync(RouteInformation info){ var razorViewEngine Ioc.CreateIRazorViewEngine(); var tempDataProvider Ioc.CreateITempDataProvider(); var serviceProvider Ioc.CreateIServiceProvider(); 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 nameinfo路由信息/param/// returns/returnspublic async Task WriteViewToFileAsync(RouteInformation info){ try { var html await RenderToStringAsync(info); if (string.IsNullOrWhiteSpace(html)) return; var path Utils.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();}四、使用方式MVC控制器配置Startup配置一次性生成方式调用一次接口即可五、源码地址Util: https://github.com/dotnetcore/UtilBing.NetCore: https://github.com/bing-framework/Bing.NetCoreRazor生成静态Html文件https://github.com/dotnetcore/Util/tree/master/src/Util.Webs/Razors 或者 https://github.com/bing-framework/Bing.NetCore/tree/master/src/Bing.Webs/Razors六、参考获取所有已注册的路由https://github.com/kobake/AspNetCore.RouteAnalyzer原文地址: https://www.cnblogs.com/jianxuanbing/p/9183359.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com