private static async Task ServePrerenderResult(HttpContext context, RenderToStringResult renderResult) { context.Response.Clear(); if (!string.IsNullOrEmpty(renderResult.RedirectUrl)) { var permanentRedirect = renderResult.StatusCode.GetValueOrDefault() == 301; context.Response.Redirect(renderResult.RedirectUrl, permanentRedirect); } else { // The Globals property exists for back-compatibility but is meaningless // for prerendering that returns complete HTML pages if (renderResult.Globals != null) { throw new InvalidOperationException($"{nameof(renderResult.Globals)} is not " + $"supported when prerendering via {nameof(UseSpaPrerendering)}(). Instead, " + $"your prerendering logic should return a complete HTML page, in which you " + $"embed any information you wish to return to the client."); } if (renderResult.StatusCode.HasValue) { context.Response.StatusCode = renderResult.StatusCode.Value; } context.Response.ContentType = "text/html"; await context.Response.WriteAsync(renderResult.Html); } }
public void HandlesNullGlobals() { // Arrange #pragma warning disable CS0618 // Type or member is obsolete var renderToStringResult = new RenderToStringResult(); #pragma warning restore CS0618 // Type or member is obsolete renderToStringResult.Globals = null; // Act var actualScript = renderToStringResult.CreateGlobalsAssignmentScript(); // Assert Assert.Equal(string.Empty, actualScript); }
public static int?GetStatusCodeFromMeta(this RenderToStringResult renderToStringResult) { // --- Parse the meta description var meta = renderToStringResult.Globals.Descendants().FirstOrDefault(o => o.Path == "meta").First.ToString(); var statusCodeMatch = Regex.Match(meta, "property=\"statusCode\" content\\s*=\\s*(?:\"(?<1>[^\"]*)\"|(?<1>\\S+))"); var statusCode = statusCodeMatch.Groups[1].Value; if (string.IsNullOrEmpty(statusCode)) { return(null); } return(Convert.ToInt32(statusCodeMatch.Groups[1].Value)); }
public void HandlesGlobalsWithCorrectStringEncoding() { // Arrange #pragma warning disable CS0618 // Type or member is obsolete var renderToStringResult = new RenderToStringResult(); #pragma warning restore CS0618 // Type or member is obsolete renderToStringResult.Globals = ToJObject(new Dictionary <string, object> { { "Va<l'u\"e", "</tag>\"'}\u260E" } }); // Act var actualScript = renderToStringResult.CreateGlobalsAssignmentScript(); // Assert var expectedScript = @"window[""Va\u003Cl\u0027u\u0022e""] = JSON.parse(""\u0022\u003C/tag\u003E\\\u0022\u0027}\u260E\u0022"");"; Assert.Equal(expectedScript, actualScript); }
private static async Task ApplyRenderResult(HttpContext context, RenderToStringResult renderResult) { if (!string.IsNullOrEmpty(renderResult.RedirectUrl)) { context.Response.Redirect(renderResult.RedirectUrl); } else { // The Globals property exists for back-compatibility but is meaningless // for prerendering that returns complete HTML pages if (renderResult.Globals != null) { throw new Exception($"{nameof(renderResult.Globals)} is not supported when prerendering via {nameof(UseSpaPrerendering)}(). Instead, your prerendering logic should return a complete HTML page, in which you embed any information you wish to return to the client."); } context.Response.ContentType = "text/html"; await context.Response.WriteAsync(renderResult.Html); } }
public void HandlesGlobalsWithMultipleProperties() { // Arrange #pragma warning disable CS0618 // Type or member is obsolete var renderToStringResult = new RenderToStringResult(); #pragma warning restore CS0618 // Type or member is obsolete renderToStringResult.Globals = ToJObject(new { FirstProperty = "first value", SecondProperty = new[] { "Array entry 0", "Array entry 1" } }); // Act var actualScript = renderToStringResult.CreateGlobalsAssignmentScript(); // Assert var expectedScript = @"window[""FirstProperty""] = JSON.parse(""\u0022first value\u0022"");" + @"window[""SecondProperty""] = JSON.parse(""[\u0022Array entry 0\u0022,\u0022Array entry 1\u0022]"");"; Assert.Equal(expectedScript, actualScript); }
public async Task <IActionResult> Index([FromServices] ISpaPrerenderer prerenderer, [FromServices] IMemoryCache cache) { IHttpRequestFeature requestFeature = this.Request.HttpContext.Features.Get <IHttpRequestFeature>(); string unencodedPathAndQuery = requestFeature.RawTarget; RenderToStringResult prerenderResult = await cache.GetOrCreateAsync(unencodedPathAndQuery, entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(10); entry.SlidingExpiration = TimeSpan.FromDays(3); return(prerenderer.RenderToString("angular/dist-server/server", customDataParameter: new { request = this.Request.AbstractHttpContextRequestInfo() })); }); this.ViewData["SpaHtml"] = prerenderResult.Html; this.ViewData["Title"] = prerenderResult.Globals["title"]; this.ViewData["Scripts"] = prerenderResult.Globals["scripts"]; this.ViewData["Styles"] = prerenderResult.Globals["styles"]; this.ViewData["Meta"] = prerenderResult.Globals["meta"]; this.ViewData["Links"] = prerenderResult.Globals["links"]; this.ViewData["TransferData"] = prerenderResult.Globals["transferData"]; return(View()); }