First, preface
In recent projects, use Util for development, using the Razor
write front page. The first use of feeling or is not accustomed to, before the end of the separation of the way developed, but the use of Util package after the development of the Angular
sense of efficiency or leverage drops.
Second, the question
In the release code, Webpack
packaging exception, hint is missing some Html
files, I looked at the corresponding directory, found that the directory is missing some HTML files, and then asked He Xi greatly, the solution is that each page needs to access to generate the corresponding HTML static file. There is a doubt as to whether there is a way to get all the routes, and then simply visit once to generate all the HTML pages.
III. Solution 3.1 Generate HTML per visit
Solution Ideas:
- Inheritance
ActionFilterAttribute
attributes, overriding execution methods
- Access is determined by whether the access is
Result
ViewResult
, if it is to generate HTML
RazorViewEngine
render from find to View
after
<summary>///generating HTML static file//</summary>public class Htmlattribute:actionfilterattribute {//<summa Ry>///build path, relative root path, example:/typings/app/app.component.html//</summary> public string Path {get; set;} <summary>///path template, Example: typings/app/{area}/{controller}/{controller}-{action}.component.html//</summ Ary> public string Template {get; set;} <summary>///execute Generate//</summary> public override async Task Onresultexecutionasync (resultexecut Ingcontext context, Resultexecutiondelegate next) {await writeviewtofileasync (context); Await base. Onresultexecutionasync (context, next); }///<summary>//write view to HTML file///</summary> Private async Task Writeviewtofileasync (resultexec Utingcontext 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 ("Failed to generate HTML static file")); }}///<summary>//Render View///</summary> protected Async task<string> Rendertostringasyn C (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.create<irazorviewengine> (); var tempdataprovider = ioc.create<itempdataprovider> (); var serviceprovider = ioc.create<iserviceprovider> (); 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, view Name, True); if (Viewresult.view = = null) throw new ArgumentNullException ($ "No View found: {viewName}"); var viewdictionary = new Viewdatadictionary (new Emptymodelmetadataprovider (), New Modelstatedictionary ()) {Model = mode L}; 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>///Get HTML Default build Path///</summary> protected virtual string GetPath (Resultexecu Tingcontext 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 One-time access generate all HTML
Solution Ideas:
- Get all registered routes
- Get
RazorHtml
routes that use custom attributes
- Bypass Routing for API interfaces
- Build
RouteData
information to find the RazorViewEngine
appropriate view in
- Build
ViewContext
to render an HTML string
- Writes the rendered HTML string to the file
Get all registered routes, here is more important, other places can also be used.
<summary>///Get all routing information///</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 page path and call if (Actiondescriptor is Pageactiondescriptor pageactiondescriptor) {in Fo. Path = Pageactiondescriptor.viewenginepath; Info. invocation = Pageactiondescriptor.relativepath; }//Route property path if (actiondescriptor.attributerouteinfo! = null) {info. Path = $ "/{actiondescriptor.attributerouteinfo.template}"; }//COntroller/action Path and call if (Actiondescriptor is Controlleractiondescriptor controlleractiondescriptor) { if (info. Path.isempty ()) {info. Path = $ "/{controlleractiondescriptor.controllername}/{controlleractiondescriptor.actionname}"; } var controllerhtmlattribute = Controlleractiondescriptor.controllertypeinfo.getcustomattribute<razorh Tmlattribute> (); if (Controllerhtmlattribute! = null) {info. FilePath = Controllerhtmlattribute.path; Info. TemplatePath = controllerhtmlattribute.template; } var Htmlattribute = controlleractiondescriptor.methodinfo.getcustomattribute<razorhtmlattribute> (); 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;}
Generating HTML static files
<summary>///Generate HTML file///</summary>///<returns></returns>public async Task Generate () {fo Reach (Var routeinformation in _routeanalyzer.getallrouteinformations ()) {//skips the processing of the API if (Routeinformati On. Path.startswith ("/api")) {continue; } await Writeviewtofileasync (routeinformation); }}///<summary>///render View As String//</summary>///<param name= "INFO" > Routing information </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 ($) cannot find the view template {info. ActionName} "); } using (var StringWriter = new StringWriter ()) {var viewdictionary = new Viewdatadictionary (New Emptymodelm Etadataprovider (), 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>///Write a view to a file///</summary>/// <param name= "INFO" > Routing information </param>///<returns></returns>public 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 ("Failed to generate HTML static file")); }}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 ("{isA} ", area). Replace ("{controller}", controller). Replace ("{action}", action); return path. ToLower ();}
Iv. Mode of Use
Five, the source address
Util
Bing.netcore
Razor generating static HTML files: Https://github.com/dotnetcore/Util/tree/master/src/Util.Webs/Razors or https://github.com/ Bing-framework/bing.netcore/tree/master/src/bing.webs/razors
Vi. references
Get all registered routes: Https://github.com/kobake/AspNetCore.RouteAnalyzer
ASP. NET Core Razor generates HTML static files