You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Apr 8, 2020. It is now read-only.
Repository navigation
This repository was archived by the owner on Apr 8, 2020. It is now read-only.
Add simpler API for invoking prerendering without using tag helper #607
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:
varrequestFeature=Request.HttpContext.Features.Get<IHttpRequestFeature>();varunencodedPathAndQuery=requestFeature.RawTarget;varunencodedAbsoluteUrl=$"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}";varprerenderResult=awaitPrerenderer.RenderToString(hostEnv.ContentRootPath,nodeServices,newJavaScriptModuleExport("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:
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.
Thank you for looking into this @SteveSandersonMS ! 💯 💯
It seemed like a change that would have to happen with the underlying Prerenderer, tried everything on my end with no luck.
Also for those wondering what the use-case for this is:
Since we're allowing .NET (MVC) to have control over the overall <html>, when we prerender applications through prerenderer.RenderToString, although we can pass variables through globals onto the window., we're still unable to effect the html that's output from the MVC View.
Being able to manipulate <title> and <meta> tags is crucial for SEO when it comes to server-rendered pages (ie: social-media deeplinking, link previews, etc)
Your example looks like it would be perfect for this!
@inject Microsoft.AspNetCore.SpaServices.Prerendering.IPrerenderer prerenderer
@{
var prerenderResult = await prerenderer.RenderToString("ClientApp/dist/main-server");
}
...
<html>
<head>
<title>@prerenderResult.Globals["pageTitle"]</title>
<!-- meta tags -->
<meta name="description" content='@prerenderResult.Globals["meta"]["description"]'>
<meta name="keywords" content='@prerenderResult.Globals["meta"]["keywords"]'>
<!-- and so on, for the remaining meta / FB: / og: / twitter: meta tags -->
<meta name="fb:app_id" content='@prerenderResult.Globals["meta"]["fb"]["appid"]'>
</head>
<body>
<app>@Html.Raw(prerenderResult.Html)</app>
</body>
</html>
One last question, would this be an alternative to the way we're currently doing things, or would all the templates need to be changed in this way? I feel that ideally they might as well all change, because eventually everyone will get to the point where they realize they need to update the Title / etc.
(On the Angular side) I have a way of extracting the title/meta data from the serialization, but I'm going to look into making it even easier & cleaner.
Ideally it'd be great to have Universal do something like this, I brought it up that normal meta manipulation won't work with .NET for the reasons above, so I'm hoping I can somehow convince them to add this in there.
The code will actually be slightly similar to the above :)
Of course some of those APIs have changed in Angular 4.x since I wrote that, but so far I have it working, and am able to extract out styles (to be placed in the correct location), Title, and only place in the correct Html from the serialized application (instead of the entire <html><head>... etc)
We're still in beta, so I'm trying to work everything out and communicate back to the Core team to make sure everything works smoothly. II should be updating it in my repository once everything is ironed out more, I'm also going to eventually abstract out some of the logic so it's much cleaner in the boot-server file. I'd imagine I'll make a PR with the similar new APis here (to this repo) once 4.x officially lands.
Thanks @MarkPieszak ,
I'm willing to help if I can.
I have a finished website that is blocked by SEO. Sorry for making pressure but it's very urgent for me :)
Not a problem totally understand!
You need Title & Meta tag support as well right?
If we can't get it within this repo, I'll at least have it within mine soon so you can patch your project with it. No worries 👍 @hheexx
Reacted by Boris Prpic and Víctor Fernández Portero
I've developed an web application built using ASP.NET Core Web API and Angular 4. My module bundler is Web Pack 2.
So I cannot use this piece of code: ViewData["SpaHtml"] = prerenderResult.Html; from my controller. I do not have any cshtml views., so I cannot send data from controller to view through ViewData["SpaHtml"].
But I would like to use server side prerendering. I would like to add metatags into head:
import { Meta } from '@angular/platform-browser';
constructor(
private metaService: Meta) {
}
let newText = "Foo data. This is test data!:)";
//metatags to publish this page at social nets
this.metaService.addTags([
// Open Graph data
{ property: 'og:title', content: newText },
{ property: 'og:description', content: newText }, {
{ property: "og:url", content: window.location.href },
{ property: 'og:image', content: "http://usiter.com/uploads/20111118/zhivotnie+koshki+kartinka+s+malenkim+kotyonkom+35121656913.jpg" }]);
You receive rendered html string from node.js.
You can do whatever you want to it and you can return it directly from controller like:
return Content(htmlStr)
@hheexx I have a way to send data to plain html. And this data correctly is added to metatags:
import { Meta } from '@angular/platform-browser';
constructor(
private metaService: Meta) {
}
let newText = "Foo data. This is test data!:)";
//metatags to publish this page at social nets
this.metaService.addTags([
// Open Graph data
{ property: 'og:title', content: newText },
{ property: 'og:description', content: newText }, {
{ property: "og:url", content: window.location.href },
{ property: 'og:image', content: "http://www.freeimageslive.co.uk/files
/images004/Italy_Venice_Canal_Grande.jpg" }]);
However, Search engines, Facebook, Twitter does not show my images when I try to post news at Facebook, Twitter or other social nets. I've explored why it happens and the reason is that SEO does not run JavaScript code. So when I post I do not see images.
I cannot use tag helper and ViewData as I've created ASP.NET Core Web API project and I do not have any ".cshtml" page.
Activity
MarkPieszak commentedon Jan 26, 2017
Thank you for looking into this @SteveSandersonMS ! 💯 💯
It seemed like a change that would have to happen with the underlying Prerenderer, tried everything on my end with no luck.
Also for those wondering what the use-case for this is:
Since we're allowing .NET (MVC) to have control over the overall
<html>, when we prerender applications through prerenderer.RenderToString, although we can pass variables throughglobalsonto thewindow., we're still unable to effect the html that's output from the MVC View.Being able to manipulate
<title>and<meta>tags is crucial for SEO when it comes to server-rendered pages (ie: social-media deeplinking, link previews, etc)Your example looks like it would be perfect for this!
One last question, would this be an alternative to the way we're currently doing things, or would all the templates need to be changed in this way? I feel that ideally they might as well all change, because eventually everyone will get to the point where they realize they need to update the Title / etc.
(On the Angular side) I have a way of extracting the title/meta data from the serialization, but I'm going to look into making it even easier & cleaner.
Ideally it'd be great to have Universal do something like this, I brought it up that normal meta manipulation won't work with .NET for the reasons above, so I'm hoping I can somehow convince them to add this in there.
hheexx commentedon Feb 22, 2017
@MarkPieszak Is there any reason not to switch to code you provided in last post?
Only thing that comes to my mind is asp-append-version attribute that is used for cache busting.
MarkPieszak commentedon Feb 22, 2017
The code will actually be slightly similar to the above :)
Of course some of those APIs have changed in Angular 4.x since I wrote that, but so far I have it working, and am able to extract out styles (to be placed in the correct location), Title, and only place in the correct Html from the serialized application (instead of the entire
<html><head>...etc)We're still in beta, so I'm trying to work everything out and communicate back to the Core team to make sure everything works smoothly. II should be updating it in my repository once everything is ironed out more, I'm also going to eventually abstract out some of the logic so it's much cleaner in the
boot-serverfile. I'd imagine I'll make a PR with the similar new APis here (to this repo) once 4.x officially lands.We're getting there though! 😄 @hheexx
hheexx commentedon Feb 22, 2017
Thanks @MarkPieszak ,
I'm willing to help if I can.
I have a finished website that is blocked by SEO. Sorry for making pressure but it's very urgent for me :)
I hope you can commit something around RC time :)
MarkPieszak commentedon Feb 22, 2017
Not a problem totally understand!
You need Title & Meta tag support as well right?
If we can't get it within this repo, I'll at least have it within mine soon so you can patch your project with it. No worries 👍 @hheexx
HaraldMuehlhoffCC commentedon Mar 2, 2017
Just on a side-note:
I'm using the code at the top of this thread in my
HomeController.I had to add
to make redirects in my react-router work:
I also had to add code to make the react-cookie work again:
(HomeController)
(Index.cshtml)
The code in boot-client (ReactReduxSPA) also doesn't take care of the cookie options, e.g. path.
NiceStepUp commentedon Jun 5, 2017
I've developed an web application built using ASP.NET Core Web API and Angular 4. My module bundler is Web Pack 2.
So I cannot use this piece of code:
ViewData["SpaHtml"] = prerenderResult.Html;from my controller. I do not have any cshtml views., so I cannot send data from controller to view throughViewData["SpaHtml"].But I would like to use server side prerendering. I would like to add metatags into head:
Is it possible to do without "ViewData"?`
hheexx commentedon Jun 5, 2017
You receive rendered html string from node.js.
You can do whatever you want to it and you can return it directly from controller like:
return Content(htmlStr)
NiceStepUp commentedon Jun 5, 2017
@hheexx ok, how can I add meta tags from controller to html page?
hheexx commentedon Jun 5, 2017
html page is in a string so you need to find a way to find the right spot and insert meta in.
mryarbles commentedon Jun 6, 2017
Why is this so poorly documented? I can't find anything online explaining exactly how to use Prerenderer directly except this github issue.
MarkPieszak commentedon Jun 6, 2017
You can see an example of it in action here @mryarbles
https://github.com/MarkPieszak/aspnetcore-angular2-universal/blob/master/Server/Controllers/HomeController.cs
NiceStepUp commentedon Jun 7, 2017
@hheexx I have a way to send data to plain html. And this data correctly is added to metatags:
However, Search engines, Facebook, Twitter does not show my images when I try to post news at Facebook, Twitter or other social nets. I've explored why it happens and the reason is that SEO does not run JavaScript code. So when I post I do not see images.
I cannot use tag helper and ViewData as I've created ASP.NET Core Web API project and I do not have any ".cshtml" page.
SteveSandersonMS commentedon Jul 3, 2017
There's now a new API for this. It looks extremely similar to the proposal in this issue. Sample usage: 94fc84a#diff-ac9fabb76766dea5d503c5a5387e88e4
Further docs will come later. This will be included in version 2.0.0 of the SpaServices package.