Add simpler API for invoking prerendering without using tag helper #607
Description
Although the asp-prerender-module
tag helper is usually the most convenient and natural way to invoke prerendering, there are some cases where you'd want to do it from controller code, or from a code block in your Razor page. For example, you might want to receive back additional custom data values from prerendering, and then maybe use them to set the page title or similar. Or you might want to change how the globals
values are serialized and delivered to the client.
Currently it is possible to do this by invoking Prerenderer.RenderToString
directly. However it's inconvenient, because you have to duplicate some non-obvious logic from the tag helper. For example, to run prerendering from controller code, currently you need something like this:
var requestFeature = Request.HttpContext.Features.Get<IHttpRequestFeature>();
var unencodedPathAndQuery = requestFeature.RawTarget;
var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}";
var prerenderResult = await Prerenderer.RenderToString(
hostEnv.ContentRootPath,
nodeServices,
new JavaScriptModuleExport("ClientApp/dist/main-server"),
unencodedAbsoluteUrl,
unencodedPathAndQuery,
/* custom data parameter */ null,
/* timeout milliseconds */ 15*1000,
Request.PathBase.ToString()
);
ViewData["SpaHtml"] = prerenderResult.Html;
ViewData["Title"] = prerenderResult.Globals["pageTitle"];
We should consider migrating this logic out of PrerenderTagHelper
and into some new DI service class that PrerenderTagHelper
starts using. Then developers will be able to grab instances of that new service class and do custom prerendering much more easily. Ideally, you'd be able to do something like this directly in a Razor view:
@inject Microsoft.AspNetCore.SpaServices.Prerendering.IPrerenderer prerenderer
@{
var prerenderResult = await prerenderer.RenderToString("ClientApp/dist/main-server");
}
...
<title>@prerenderResult.Globals["pageTitle"]</title>
<app>@Html.Raw(prerenderResult.Html)</app>
There could be an options param for overriding things like the request URL, timeout, etc., but by default it would use values from the context automatically like asp-prerender-module
already does.