Implement and document asp-prerender-data

This commit is contained in:
SteveSandersonMS
2016-06-21 15:46:52 +01:00
parent 1a53411046
commit ea0a32a15b
5 changed files with 45 additions and 8 deletions

View File

@@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
private const string PrerenderModuleAttributeName = "asp-prerender-module";
private const string PrerenderExportAttributeName = "asp-prerender-export";
private const string PrerenderWebpackConfigAttributeName = "asp-prerender-webpack-config";
private const string PrerenderDataAttributeName = "asp-prerender-data";
private static INodeServices _fallbackNodeServices; // Used only if no INodeServices was registered with DI
private readonly string _applicationBasePath;
@@ -51,6 +52,9 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
[HtmlAttributeName(PrerenderWebpackConfigAttributeName)]
public string WebpackConfigPath { get; set; }
[HtmlAttributeName(PrerenderDataAttributeName)]
public object CustomDataParameter { get; set; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
@@ -67,7 +71,8 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
WebpackConfig = WebpackConfigPath
},
request.GetEncodedUrl(),
request.Path + request.QueryString.Value);
request.Path + request.QueryString.Value,
CustomDataParameter);
output.Content.SetHtmlContent(result.Html);
// Also attach any specified globals to the 'window' object. This is useful for transferring

View File

@@ -22,7 +22,8 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
INodeServices nodeServices,
JavaScriptModuleExport bootModule,
string requestAbsoluteUrl,
string requestPathAndQuery)
string requestPathAndQuery,
object customDataParameter)
{
return nodeServices.InvokeExport<RenderToStringResult>(
NodeScript.Value.FileName,
@@ -30,7 +31,8 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
applicationBasePath,
bootModule,
requestAbsoluteUrl,
requestPathAndQuery);
requestPathAndQuery,
customDataParameter);
}
}
}

View File

@@ -81,6 +81,34 @@ If you try running your app now, you should see the HTML snippet generated by yo
As you can see, your JavaScript code receives context information (such as the URL being requested), and returns a `Promise` so that it can asynchronously supply the markup to be injected into the page. You can put whatever logic you like here, but typically you'll want to execute a component from your Angular 2 / React / etc. application.
**Passing data from .NET code into JavaScript code**
If you want to supply additional data to the JavaScript function that performs your prerendering, you can use the `asp-prerender-data` attribute. You can give any value as long as it's JSON-serializable. Bear in mind that it will be serialized and sent as part of the remote procedure call (RPC) to Node.js, so avoid trying to pass massive amounts of data.
For example, in your `cshtml`,
<div id="my-spa" asp-prerender-module="ClientApp/boot-server"
asp-prerender-data="new {
IsGoldUser = true,
Cookies = ViewContext.HttpContext.Request.Cookies
}""></div>
Now in your JavaScript prerendering function, you can access this data by reading `params.data`, e.g.:
```javascript
module.exports = function(params) {
return new Promise(function (resolve, reject) {
var result = '<h1>Hello world!</h1>'
+ '<p>Is gold user: ' + params.data.isGoldUser + '</p>'
+ '<p>Number of cookies: ' + params.data.cookies.length + '</p>';
resolve({ html: result });
});
};
```
Notice that the property names are received in JavaScript-style casing (e.g., `isGoldUser`) even though they were sent in C#-style casing (e.g., `IsGoldUser`). This is because of how the JSON serialization is configured by default.
**Passing data from server-side to client-side code**
If, as well as returning HTML, you also want to pass some contextual data from your server-side code to your client-side code, you can supply a `globals` object alongside the initial `html`, e.g.:
@@ -245,7 +273,7 @@ At this stage, run `webpack` on the command line to build `wwwroot/dist/main.js`
You can now run your React code on the client by adding the following to one of your MVC views:
<div id="my-spa"></div>
<div id="my-spa"></div>
<script src="/dist/main.js"></script>
#### Running React code on the server

View File

@@ -1,6 +1,6 @@
{
"name": "aspnet-prerendering",
"version": "1.0.1",
"version": "1.0.2",
"description": "Helpers for server-side rendering of JavaScript applications in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js",
"scripts": {

View File

@@ -24,6 +24,7 @@ export interface BootFuncParams {
url: string; // e.g., '/some/path'
absoluteUrl: string; // e.g., 'https://example.com:1234/some/path'
domainTasks: Promise<any>;
data: any; // any custom object passed through from .NET
}
export interface BootModuleInfo {
@@ -32,7 +33,7 @@ export interface BootModuleInfo {
webpackConfig?: string;
}
export function renderToString(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string) {
export function renderToString(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any) {
findBootFunc(applicationBasePath, bootModule, (findBootFuncError, bootFunc) => {
if (findBootFuncError) {
callback(findBootFuncError, null);
@@ -51,7 +52,8 @@ export function renderToString(callback: RenderToStringCallback, applicationBase
origin: parsedAbsoluteRequestUrl.protocol + '//' + parsedAbsoluteRequestUrl.host,
url: requestPathAndQuery,
absoluteUrl: absoluteRequestUrl,
domainTasks: domainTaskCompletionPromise
domainTasks: domainTaskCompletionPromise,
data: customDataParameter
};
// Open a new domain that can track all the async tasks involved in the app's execution
@@ -86,7 +88,7 @@ function findBootModule<T>(applicationBasePath: string, bootModule: BootModuleIn
const bootModuleNameFullPath = path.resolve(applicationBasePath, bootModule.moduleName);
if (bootModule.webpackConfig) {
const webpackConfigFullPath = path.resolve(applicationBasePath, bootModule.webpackConfig);
let aspNetWebpackModule: any;
try {
aspNetWebpackModule = require('aspnet-webpack');