From 948bf9d22cc88f8221f9084699ea9cd92ff5cd69 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Sun, 11 Mar 2018 12:05:35 +0100 Subject: [PATCH 01/11] move prerendering to its own project --- Blazor.sln | 26 +- samples/PrerenderingApp.Client/Home.cshtml | 12 + samples/PrerenderingApp.Client/MyInput.cshtml | 10 + samples/PrerenderingApp.Client/MyList.cshtml | 17 ++ .../PrerenderingApp.Client.csproj | 15 ++ samples/PrerenderingApp.Client/Program.cs | 33 +++ .../wwwroot/customJsFileForTests.js | 3 + .../PrerenderingApp.Client/wwwroot/index.html | 12 + .../PrerenderingApp.Server.csproj | 17 ++ samples/PrerenderingApp.Server/Program.cs | 51 ++++ samples/PrerenderingApp.Server/Startup.cs | 29 +++ ....AspNetCore.Blazor.Server.Rendering.csproj | 15 ++ .../PreRenderer.cs | 239 ++++++++++++++++++ .../PreServiceProvider.cs | 45 ++++ .../PreUriHelper.cs | 34 +++ .../Properties/AssemblyInfo.cs | 3 + 16 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 samples/PrerenderingApp.Client/Home.cshtml create mode 100644 samples/PrerenderingApp.Client/MyInput.cshtml create mode 100644 samples/PrerenderingApp.Client/MyList.cshtml create mode 100644 samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj create mode 100644 samples/PrerenderingApp.Client/Program.cs create mode 100644 samples/PrerenderingApp.Client/wwwroot/customJsFileForTests.js create mode 100644 samples/PrerenderingApp.Client/wwwroot/index.html create mode 100644 samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj create mode 100644 samples/PrerenderingApp.Server/Program.cs create mode 100644 samples/PrerenderingApp.Server/Startup.cs create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/Properties/AssemblyInfo.cs diff --git a/Blazor.sln b/Blazor.sln index 68b8a2f64..e274ec045 100644 --- a/Blazor.sln +++ b/Blazor.sln @@ -77,7 +77,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorHosted-CSharp.Client" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorHosted-CSharp.Server", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorHosted-CSharp\BlazorHosted-CSharp.Server\BlazorHosted-CSharp.Server.csproj", "{78ED9932-0912-4F36-8F82-33DE850E7A33}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorHosted-CSharp.Shared", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorHosted-CSharp\BlazorHosted-CSharp.Shared\BlazorHosted-CSharp.Shared.csproj", "{F3E02B21-1127-431A-B832-0E53CB72097B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorHosted-CSharp.Shared", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorHosted-CSharp\BlazorHosted-CSharp.Shared\BlazorHosted-CSharp.Shared.csproj", "{F3E02B21-1127-431A-B832-0E53CB72097B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Prerendering", "Prerendering", "{0A6A1E7D-2236-4695-A5B1-0A82EEED0B6C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Server.Rendering", "src\Microsoft.AspNetCore.Blazor.Server.Rendering\Microsoft.AspNetCore.Blazor.Server.Rendering.csproj", "{9C424433-8AA6-452B-BA9E-01ACD2852176}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrerenderingApp.Client", "samples\PrerenderingApp.Client\PrerenderingApp.Client.csproj", "{034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrerenderingApp.Server", "samples\PrerenderingApp.Server\PrerenderingApp.Server.csproj", "{A61788D9-3764-4BC5-A5BB-118D4A10BBEB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Razor.Extensions.Test", "test\Microsoft.AspNetCore.Blazor.Razor.Extensions.Test\Microsoft.AspNetCore.Blazor.Razor.Extensions.Test.csproj", "{FF25111E-5A3E-48A3-96D8-08A2C5A2A91C}" EndProject @@ -291,6 +299,18 @@ Global {F3E02B21-1127-431A-B832-0E53CB72097B}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU {F3E02B21-1127-431A-B832-0E53CB72097B}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3E02B21-1127-431A-B832-0E53CB72097B}.Release|Any CPU.Build.0 = Release|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.Release|Any CPU.Build.0 = Release|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Release|Any CPU.Build.0 = Release|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Release|Any CPU.Build.0 = Release|Any CPU {F3E02B21-1127-431A-B832-0E53CB72097B}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU {FF25111E-5A3E-48A3-96D8-08A2C5A2A91C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF25111E-5A3E-48A3-96D8-08A2C5A2A91C}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -386,6 +406,10 @@ Global {7549444A-9C81-44DE-AD0D-2C55501EAAC7} = {73DA1DFD-79F0-4BA2-B0B6-4F3A21D2C3F8} {78ED9932-0912-4F36-8F82-33DE850E7A33} = {73DA1DFD-79F0-4BA2-B0B6-4F3A21D2C3F8} {F3E02B21-1127-431A-B832-0E53CB72097B} = {73DA1DFD-79F0-4BA2-B0B6-4F3A21D2C3F8} + {0A6A1E7D-2236-4695-A5B1-0A82EEED0B6C} = {F5FDD4E5-6A52-4A86-BE5E-5E42CB1DC8DA} + {9C424433-8AA6-452B-BA9E-01ACD2852176} = {B867E038-B3CE-43E3-9292-61568C46CDEB} + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D} = {0A6A1E7D-2236-4695-A5B1-0A82EEED0B6C} + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB} = {0A6A1E7D-2236-4695-A5B1-0A82EEED0B6C} {FF25111E-5A3E-48A3-96D8-08A2C5A2A91C} = {ADA3AE29-F6DE-49F6-8C7C-B321508CAE8E} {43E39257-7DC1-46BD-9BD9-2319A1313D07} = {F563ABB6-85FB-4CFC-B0D2-1D5130E8246D} {9088E4E4-B855-457F-AE9E-D86709A5E1F4} = {F563ABB6-85FB-4CFC-B0D2-1D5130E8246D} diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml new file mode 100644 index 000000000..5bf02c691 --- /dev/null +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -0,0 +1,12 @@ +

Hello, world!

+ + + + + + +
+ + + + diff --git a/samples/PrerenderingApp.Client/MyInput.cshtml b/samples/PrerenderingApp.Client/MyInput.cshtml new file mode 100644 index 000000000..8fdd14ca2 --- /dev/null +++ b/samples/PrerenderingApp.Client/MyInput.cshtml @@ -0,0 +1,10 @@ +@using System.Diagnostics + + + + +@functions{ + + + +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/MyList.cshtml b/samples/PrerenderingApp.Client/MyList.cshtml new file mode 100644 index 000000000..b46bcbc43 --- /dev/null +++ b/samples/PrerenderingApp.Client/MyList.cshtml @@ -0,0 +1,17 @@ +@foreach (var item in items) +{ +
@item
+} + +@functions { + + int[] items = new[] {1, 2, 3, 4}; + + + protected override void OnInit() + { + base.OnInit(); + + items = new[] {6, 7, 8, 9}; + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj b/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj new file mode 100644 index 000000000..a64eebc99 --- /dev/null +++ b/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + + + + + + + + diff --git a/samples/PrerenderingApp.Client/Program.cs b/samples/PrerenderingApp.Client/Program.cs new file mode 100644 index 000000000..38e13e7fe --- /dev/null +++ b/samples/PrerenderingApp.Client/Program.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using Microsoft.AspNetCore.Blazor.Browser.Http; +using Microsoft.AspNetCore.Blazor.Browser.Rendering; +using Microsoft.AspNetCore.Blazor.Browser.Services; +using Microsoft.AspNetCore.Blazor.Components; +using Microsoft.AspNetCore.Blazor.Rendering; +using Microsoft.AspNetCore.Blazor.RenderTree; +using Microsoft.AspNetCore.Blazor.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace PrerenderingApp.Client +{ + public class Program + { + static void Main(string[] args) + { + new BrowserRenderer().AddComponent("app"); + } + + /*static void Server(string[] args) + { + var renderer = new PreRenderer();//.AddComponent("app"); + renderer.DoStuff(); + }*/ + } +} diff --git a/samples/PrerenderingApp.Client/wwwroot/customJsFileForTests.js b/samples/PrerenderingApp.Client/wwwroot/customJsFileForTests.js new file mode 100644 index 000000000..5183d9fa3 --- /dev/null +++ b/samples/PrerenderingApp.Client/wwwroot/customJsFileForTests.js @@ -0,0 +1,3 @@ +// This is only used for E2E tests to verify that we're correctly serving static content. +// Later this will be replaced with something more useful. +window.customJsWasLoaded = true; diff --git a/samples/PrerenderingApp.Client/wwwroot/index.html b/samples/PrerenderingApp.Client/wwwroot/index.html new file mode 100644 index 000000000..ed1a339a4 --- /dev/null +++ b/samples/PrerenderingApp.Client/wwwroot/index.html @@ -0,0 +1,12 @@ + + + + + Sample Blazor app + + + Loading... + + + + diff --git a/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj b/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj new file mode 100644 index 000000000..0eafdf5e0 --- /dev/null +++ b/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp2.0 + + + + + + + + + + + + + diff --git a/samples/PrerenderingApp.Server/Program.cs b/samples/PrerenderingApp.Server/Program.cs new file mode 100644 index 000000000..53f29754f --- /dev/null +++ b/samples/PrerenderingApp.Server/Program.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Blazor.Server.Rendering; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace PrerenderingApp.Server +{ + public class Program + { + public static void Main(string[] args) + { + var directory = Directory.GetCurrentDirectory(); + var currentDirectory = Environment.CurrentDirectory; + var codeBase = Assembly.GetEntryAssembly().CodeBase; + var location = Assembly.GetEntryAssembly().Location; + //AssemblyLoadContext.Default.Resolving += Default_Resolving; + + /*var prog = typeof(Client.Program); + var method = prog.GetMethod("Server", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + method.Invoke(null, new object[] { null });*/ + + var renderer = new PreRenderer();//.AddComponent("app"); + renderer.DoStuff(); + + BuildWebHost(args).Run(); + } + + private static System.Reflection.Assembly Default_Resolving(AssemblyLoadContext arg1, System.Reflection.AssemblyName arg2) + { + var location = Assembly.GetEntryAssembly().Location; + var directoryName = Path.GetDirectoryName(location); + var assemblyPath = Path.Combine(directoryName, arg2.Name + ".dll"); + return arg1.LoadFromAssemblyPath(assemblyPath); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseConfiguration(new ConfigurationBuilder() + .AddCommandLine(args) + .Build()) + .UseStartup() + .Build(); + } +} diff --git a/samples/PrerenderingApp.Server/Startup.cs b/samples/PrerenderingApp.Server/Startup.cs new file mode 100644 index 000000000..a940faf61 --- /dev/null +++ b/samples/PrerenderingApp.Server/Startup.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace PrerenderingApp.Server +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseBlazor(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj new file mode 100644 index 000000000..d4336cde8 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs new file mode 100644 index 000000000..a12c8d937 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.AspNetCore.Blazor.Components; +using Microsoft.AspNetCore.Blazor.Rendering; +using Microsoft.AspNetCore.Blazor.RenderTree; + +namespace Microsoft.AspNetCore.Blazor.Server.Rendering +{ + public class PreRenderer : Renderer + { + public PreRenderer() : this(new PreServiceProvider()) + { + + } + + public PreRenderer(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public void DoStuff() + { + var component = InstantiateComponent(typeof(TComponent)); + var componentId = AssignComponentId(component); + component.SetParameters(ParameterCollection.Empty); + } + + protected override void UpdateDisplay(RenderBatch renderBatch) + { + var sb = new StringBuilder(); + + foreach (var u in renderBatch.UpdatedComponents) + { + UpdateComponent(sb, renderBatch, u.ComponentId, u.Edits, renderBatch.ReferenceFrames); + + } + + foreach (var componentID in renderBatch.DisposedComponentIDs) + { + DisposeComponent(componentID); + } + + var s = sb.ToString(); + } + + private void DisposeComponent(int componentId) + { + + } + + private IList handledComponents = new List(); + + private void UpdateComponent( + StringBuilder sb, + RenderBatch renderBatch, + int componentId, + ArraySegment edits, + ArrayRange referenceFrames) + { + if (handledComponents.Contains(componentId)) return; + handledComponents.Add(componentId); + ApplyEdit(sb, renderBatch, componentId, 0, edits, referenceFrames); + } + + private void ApplyEdit( + StringBuilder sb, + RenderBatch renderBatch, + int componentId, + int childIndex, + ArraySegment edits, + ArrayRange referenceFrames) + { + //var currentDepth = 0; + var childIndexAtCurrentDepth = childIndex; + var maxEditIndexExcl = edits.Offset + edits.Count; + + foreach (var edit in edits) + { + switch (edit.Type) + { + case RenderTreeEditType.PrependFrame: + var frame = referenceFrames.Array[edit.ReferenceFrameIndex]; + InsertFrame( + sb, + renderBatch, + componentId, + childIndexAtCurrentDepth + edit.SiblingIndex, + referenceFrames, + frame, + edit.ReferenceFrameIndex); + break; + case RenderTreeEditType.RemoveFrame: + break; + case RenderTreeEditType.SetAttribute: + break; + case RenderTreeEditType.RemoveAttribute: + break; + case RenderTreeEditType.UpdateText: + break; + case RenderTreeEditType.StepIn: + break; + case RenderTreeEditType.StepOut: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + private int InsertFrame( + StringBuilder sb, + RenderBatch renderBatch, + int componentId, + int childIndex, + ArrayRange frames, + RenderTreeFrame frame, int frameIndex + ) + { + switch (frame.FrameType) + { + case RenderTreeFrameType.Element: + InsertElement(sb, renderBatch, componentId, childIndex, frames, frame, frameIndex); + return 1; + case RenderTreeFrameType.Text: + InsertText(sb, childIndex, frame); + return 1; + case RenderTreeFrameType.Component: + InsertComponent(sb, renderBatch, childIndex, frame, frames); + return 1; + case RenderTreeFrameType.Region: + return InsertFrameRange( + sb, + renderBatch, + componentId, + childIndex, + frames, + frameIndex + 1, + frameIndex + frame.ElementSubtreeLength); + case RenderTreeFrameType.Attribute: + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void InsertComponent( + StringBuilder sb, + RenderBatch renderBatch, + int childIndex, + RenderTreeFrame frame, + ArrayRange frames) + { + sb.Append(""); + var u = renderBatch.UpdatedComponents.Single(c => c.ComponentId == frame.ComponentId); + UpdateComponent(sb, renderBatch, u.ComponentId, u.Edits, frames); + sb.Append(""); + } + + private void InsertText( + StringBuilder sb, + int childIndex, + RenderTreeFrame frame) + { + var textContent = frame.TextContent; + sb.Append(textContent); + } + + private void InsertElement( + StringBuilder sb, + RenderBatch renderBatch, + int componentId, + int childIndex, + ArrayRange frames, + RenderTreeFrame frame, + int frameIndex) + { + var tagName = frame.ElementName; + sb.Append("<"); + sb.Append(tagName); + + var x = frameIndex + frame.ElementSubtreeLength; + + for (var di = frameIndex + 1; di < x; di++) + { + var dframe = frames.Array[di]; + if (dframe.FrameType == RenderTreeFrameType.Attribute) + { + ApplyAttribute(sb, componentId, dframe); + } + else + { + sb.Append(">"); + InsertFrameRange(sb, renderBatch, componentId, 0, frames, di, x); + sb.Append(""); + } + + private int InsertFrameRange( + StringBuilder sb, + RenderBatch renderBatch, + int componentId, + int childIndex, + ArrayRange frames, + int di, + int i1) + { + var org = childIndex; + for (var i = di; i < i1; i++) + { + var frame = frames.Array[i]; + var numAdded = InsertFrame(sb, renderBatch, componentId, childIndex, frames, frame, i); + childIndex += numAdded; + + var subTreeLength = frame.ElementSubtreeLength; + if (subTreeLength > 1) + { + i += subTreeLength - 1; + } + } + + return (childIndex - org); + } + + private void ApplyAttribute(StringBuilder sb, int componentId, RenderTreeFrame dframe) + { + var attributeName = dframe.AttributeName; + var value = dframe.AttributeValue; + sb.Append(" "); + sb.Append(attributeName); + sb.Append("=\""); + sb.Append(value); + sb.Append("\""); + } + } +} diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs new file mode 100644 index 000000000..234e56f5a --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs @@ -0,0 +1,45 @@ +using System; +using System.Net.Http; +using Microsoft.AspNetCore.Blazor.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Blazor.Server.Rendering +{ + public class PreServiceProvider : IServiceProvider + { + private readonly IServiceProvider _underlyingProvider; + + /// + /// Constructs an instance of . + /// + public PreServiceProvider() : this(null) + { + } + + /// + /// Constructs an instance of . + /// + /// A callback that can be used to configure the . + public PreServiceProvider(Action configure) + { + var serviceCollection = new ServiceCollection(); + AddDefaultServices(serviceCollection); + configure?.Invoke(serviceCollection); + _underlyingProvider = serviceCollection.BuildServiceProvider(); + } + + /// + public object GetService(Type serviceType) + => _underlyingProvider.GetService(serviceType); + + private void AddDefaultServices(ServiceCollection serviceCollection) + { + var uriHelper = new PreUriHelper(); + serviceCollection.AddSingleton(uriHelper); + serviceCollection.AddSingleton(new HttpClient(/*new BrowserHttpMessageHandler()*/) + { + BaseAddress = new Uri(uriHelper.GetBaseUriPrefix()) + }); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs new file mode 100644 index 000000000..6ed2bf2d1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs @@ -0,0 +1,34 @@ +using System; +using Microsoft.AspNetCore.Blazor.Services; + +namespace Microsoft.AspNetCore.Blazor.Server.Rendering +{ + public class PreUriHelper : IUriHelper + { + public string GetAbsoluteUri() + { + throw new NotImplementedException(); + } + + public event EventHandler OnLocationChanged; + public Uri ToAbsoluteUri(string href) + { + throw new NotImplementedException(); + } + + public string GetBaseUriPrefix() + { + return "http://localhost:56484/"; + } + + public string ToBaseRelativePath(string baseUriPrefix, string locationAbsolute) + { + throw new NotImplementedException(); + } + + protected virtual void OnOnLocationChanged(string e) + { + OnLocationChanged?.Invoke(this, e); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..1f2a6fd15 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor.Cli")] From 5b0cbfa0639167bc245fc27373f1ce4dfa5349d6 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Sun, 11 Mar 2018 18:56:32 +0100 Subject: [PATCH 02/11] add prerendering middleware --- samples/PrerenderingApp.Server/Startup.cs | 5 +- .../BlazorPrerenderingAppBuilderExtensions.cs | 12 +++ .../BlazorPrerenderingMiddleware.cs | 77 +++++++++++++++++++ .../BlazorPrerenderingSpaBuilderExtensions.cs | 12 +++ ....AspNetCore.Blazor.Server.Rendering.csproj | 13 +++- .../BlazorAppBuilderExtensions.cs | 13 +++- src/anglesharp/AngleSharpBuilder/Program.cs | 1 + 7 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs create mode 100644 src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs diff --git a/samples/PrerenderingApp.Server/Startup.cs b/samples/PrerenderingApp.Server/Startup.cs index a940faf61..34e49151b 100644 --- a/samples/PrerenderingApp.Server/Startup.cs +++ b/samples/PrerenderingApp.Server/Startup.cs @@ -3,7 +3,10 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Blazor.Server.Rendering; namespace PrerenderingApp.Server { @@ -23,7 +26,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseDeveloperExceptionPage(); } - app.UseBlazor(); + app.UseBlazorPrerendering(); } } } diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs new file mode 100644 index 000000000..0cc4091f7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Microsoft.AspNetCore.Blazor.Server.Rendering +{ + public static class BlazorPrerenderingAppBuilderExtensions + { + public static void UseBlazorPrerendering(this IApplicationBuilder app) + { + app.UseBlazor(c => c.UseBlazorPrerendering()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs new file mode 100644 index 000000000..09f6eb4c1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using AngleSharp; +using AngleSharp.Html; +using AngleSharp.Parser.Html; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.SpaServices; +using Microsoft.AspNetCore.SpaServices.StaticFiles; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Blazor.Server.Rendering +{ + public class BlazorPrerenderingMiddleware + { + private readonly RequestDelegate _next; + + public BlazorPrerenderingMiddleware(RequestDelegate next) + { + _next = next; + } + + public Task Invoke(HttpContext context) + { + + + return _next(context); + } + + public static void Attach(ISpaBuilder spaBuilder) + { + if (spaBuilder == null) + throw new ArgumentNullException(nameof(spaBuilder)); + IApplicationBuilder applicationBuilder = spaBuilder.ApplicationBuilder; + + SpaOptions options = spaBuilder.Options; + var fileOptions = options.DefaultPageStaticFileOptions; + applicationBuilder.Use((context, next) => + { + context.Request.Path = options.DefaultPage; + return next(); + }); + + applicationBuilder.Use((context, next) => + { + var subpath = context.Request.Path; + var fileInfo = fileOptions.FileProvider.GetFileInfo(subpath); + if (fileInfo.Exists) + { + fileOptions.ContentTypeProvider.TryGetContentType(subpath, out var contentType); + + using (var stream = fileInfo.CreateReadStream()) + using (var reader = new StreamReader(stream)) + { + var html = reader.ReadToEnd(); + + var tokenizer = new HtmlTokenizer(new TextSource(html), HtmlEntityService.Resolver); + + + } + + context.Response.StatusCode = 200; + context.Response.ContentType = contentType; + context.Response.ContentLength = fileInfo.Length; + //stream.CopyTo(context.Response.Body); + + return Task.FromResult(0); + } + + return next(); + }); + } + } + +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs new file mode 100644 index 000000000..d2d7fb4ff --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.SpaServices; + +namespace Microsoft.AspNetCore.Blazor.Server.Rendering +{ + public static class BlazorPrerenderingSpaBuilderExtensions + { + public static void UseBlazorPrerendering(this ISpaBuilder spa) + { + BlazorPrerenderingMiddleware.Attach(spa); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj index d4336cde8..db6e7fece 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj @@ -1,15 +1,26 @@ - netstandard2.0 + netcoreapp2.0 + + + + + AngleSharpBuilder + False + TargetFramework=netcoreapp2.0 + false + + + diff --git a/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs index 9c74a6176..3fcd3d15a 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Blazor.Server; using Microsoft.AspNetCore.StaticFiles; @@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Net.Http.Headers; using System.Net.Mime; +using Microsoft.AspNetCore.SpaServices; namespace Microsoft.AspNetCore.Builder { @@ -21,14 +23,16 @@ public static class BlazorAppBuilderExtensions /// /// Any type from the client app project. This is used to identify the client app assembly. /// + /// public static void UseBlazor( - this IApplicationBuilder applicationBuilder) + this IApplicationBuilder applicationBuilder, + Action configuration = null) { var clientAssemblyInServerBinDir = typeof(TProgram).Assembly; applicationBuilder.UseBlazor(new BlazorOptions { ClientAssemblyPath = clientAssemblyInServerBinDir.Location, - }); + }, configuration); } /// @@ -36,9 +40,11 @@ public static void UseBlazor( /// /// /// + /// public static void UseBlazor( this IApplicationBuilder applicationBuilder, - BlazorOptions options) + BlazorOptions options, + Action configuration = null) { // TODO: Make the .blazor.config file contents sane // Currently the items in it are bizarre and don't relate to their purpose, @@ -81,6 +87,7 @@ public static void UseBlazor( childAppBuilder.UseSpa(spa => { spa.Options.DefaultPageStaticFileOptions = distDirStaticFiles; + configuration?.Invoke(spa); }); }); } diff --git a/src/anglesharp/AngleSharpBuilder/Program.cs b/src/anglesharp/AngleSharpBuilder/Program.cs index 474d7a223..655927f88 100644 --- a/src/anglesharp/AngleSharpBuilder/Program.cs +++ b/src/anglesharp/AngleSharpBuilder/Program.cs @@ -65,6 +65,7 @@ private static void WriteModifiedAssembly(Assembly assembly, string outputDir) AddInternalsVisibleTo(moduleDefinition, "Microsoft.AspNetCore.Blazor.Build"); AddInternalsVisibleTo(moduleDefinition, "Microsoft.AspNetCore.Blazor.Razor.Extensions"); + AddInternalsVisibleTo(moduleDefinition, "Microsoft.AspNetCore.Blazor.Server.Rendering"); RemoveStrongName(moduleDefinition); SetAssemblyName(moduleDefinition, "Microsoft.AspNetCore.Blazor.AngleSharp"); From 748c5fd9830a2316b797de282eb7b1fb83acccd4 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Sun, 11 Mar 2018 19:55:35 +0100 Subject: [PATCH 03/11] prerendering hello world --- samples/PrerenderingApp.Server/Program.cs | 2 +- .../BlazorPrerenderingMiddleware.cs | 56 +++++++++++-------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/samples/PrerenderingApp.Server/Program.cs b/samples/PrerenderingApp.Server/Program.cs index 53f29754f..7c7a5db43 100644 --- a/samples/PrerenderingApp.Server/Program.cs +++ b/samples/PrerenderingApp.Server/Program.cs @@ -20,7 +20,7 @@ public static void Main(string[] args) var currentDirectory = Environment.CurrentDirectory; var codeBase = Assembly.GetEntryAssembly().CodeBase; var location = Assembly.GetEntryAssembly().Location; - //AssemblyLoadContext.Default.Resolving += Default_Resolving; + AssemblyLoadContext.Default.Resolving += Default_Resolving; /*var prog = typeof(Client.Program); var method = prog.GetMethod("Server", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs index 09f6eb4c1..dd6359930 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Text; using System.Threading.Tasks; using AngleSharp; using AngleSharp.Html; @@ -15,20 +16,6 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { public class BlazorPrerenderingMiddleware { - private readonly RequestDelegate _next; - - public BlazorPrerenderingMiddleware(RequestDelegate next) - { - _next = next; - } - - public Task Invoke(HttpContext context) - { - - - return _next(context); - } - public static void Attach(ISpaBuilder spaBuilder) { if (spaBuilder == null) @@ -51,27 +38,52 @@ public static void Attach(ISpaBuilder spaBuilder) { fileOptions.ContentTypeProvider.TryGetContentType(subpath, out var contentType); + context.Response.StatusCode = 200; + context.Response.ContentType = contentType; + using (var stream = fileInfo.CreateReadStream()) using (var reader = new StreamReader(stream)) { var html = reader.ReadToEnd(); - var tokenizer = new HtmlTokenizer(new TextSource(html), HtmlEntityService.Resolver); - - + var content = Prerender(html); + context.Response.ContentLength = content.Length; + using (var writer = new StreamWriter(context.Response.Body, Encoding.Default, 4096, leaveOpen: true)) + { + writer.Write(content); + } } - context.Response.StatusCode = 200; - context.Response.ContentType = contentType; - context.Response.ContentLength = fileInfo.Length; - //stream.CopyTo(context.Response.Body); - return Task.FromResult(0); } return next(); }); } + + private static string Prerender(string html) + { + var tokenizer = new HtmlTokenizer(new TextSource(html), HtmlEntityService.Resolver); + + while (true) + { + var token = tokenizer.Get(); + switch (token.Type) + { + case HtmlTokenType.EndOfFile: + return @" + + + + Sample Blazor app + + +

Hello prerendering

+ +"; + } + } + } } } \ No newline at end of file From b8fa1a91f00df1a2b67926c63fa364ebf53c7bcd Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Sun, 11 Mar 2018 20:06:35 +0100 Subject: [PATCH 04/11] prerendering hello world using index.html content --- .../BlazorPrerenderingMiddleware.cs | 74 ++++++++++++++++--- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs index dd6359930..4c3ff3a4a 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; using AngleSharp; @@ -61,29 +63,77 @@ public static void Attach(ISpaBuilder spaBuilder) }); } - private static string Prerender(string html) + private static string Prerender(string htmlTemplate) { - var tokenizer = new HtmlTokenizer(new TextSource(html), HtmlEntityService.Resolver); + // copied from IndexHtmlFileProvider.cs + var resultBuilder = new StringBuilder(); + // Search for a tag of the form , and replace + // it with the prerendered content + var tokenizer = new HtmlTokenizer( + new TextSource(htmlTemplate), + HtmlEntityService.Resolver); + var currentRangeStartPos = 0; + var isInBlazorBootTag = false; + var resumeOnNextToken = false; while (true) { var token = tokenizer.Get(); + if (resumeOnNextToken) + { + resumeOnNextToken = false; + currentRangeStartPos = token.Position.Position; + } + switch (token.Type) { + case HtmlTokenType.StartTag: + { + // Only do anything special if this is a Blazor boot tag + var tag = token.AsTag(); + if (IsBlazorBootTag(tag)) + { + // First, emit the original source text prior to this special tag, since + // we want that to be unchanged + resultBuilder.Append(htmlTemplate, currentRangeStartPos, token.Position.Position - currentRangeStartPos - 1); + + // Instead of emitting the source text for this special tag, emit a fully- + // configured Blazor boot script tag + AppendScriptTagWithBootConfig(resultBuilder); + + // Set a flag so we know not to emit anything else until the special + // tag is closed + isInBlazorBootTag = true; + } + break; + } + + case HtmlTokenType.EndTag: + // If this is an end tag corresponding to the Blazor boot script tag, we + // can switch back into the mode of emitting the original source text + if (isInBlazorBootTag) + { + isInBlazorBootTag = false; + resumeOnNextToken = true; + } + break; + case HtmlTokenType.EndOfFile: - return @" - - - - Sample Blazor app - - -

Hello prerendering

- -"; + // Finally, emit any remaining text from the original source file + resultBuilder.Append(htmlTemplate, currentRangeStartPos, htmlTemplate.Length - currentRangeStartPos); + return resultBuilder.ToString(); } } } + + private static bool IsBlazorBootTag(HtmlTagToken tag) + => string.Equals(tag.Name, "app", StringComparison.Ordinal); + + private static void AppendScriptTagWithBootConfig( + StringBuilder resultBuilder) + { + resultBuilder.AppendLine("

Hello Prerendering

"); + } } } \ No newline at end of file From 893e2b943d70166afa58062ad9e6808d7dce58f6 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Sun, 11 Mar 2018 22:08:26 +0100 Subject: [PATCH 05/11] working prerendering (some limitations) --- samples/PrerenderingApp.Client/Home.cshtml | 22 ++++-- samples/PrerenderingApp.Client/MyInput.cshtml | 11 +-- samples/PrerenderingApp.Client/MyList.cshtml | 1 - samples/PrerenderingApp.Client/Program.cs | 6 -- samples/PrerenderingApp.Server/Program.cs | 19 +---- samples/PrerenderingApp.Server/Startup.cs | 2 +- .../BlazorPrerenderingAppBuilderExtensions.cs | 2 +- .../BlazorPrerenderingMiddleware.cs | 27 ++++--- .../BlazorPrerenderingSpaBuilderExtensions.cs | 4 +- .../PreRenderer.cs | 75 +++++++++---------- 10 files changed, 73 insertions(+), 96 deletions(-) diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml index 5bf02c691..13df57f27 100644 --- a/samples/PrerenderingApp.Client/Home.cshtml +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -1,12 +1,22 @@ -

Hello, world!

+

Prerendering Sample

+

Input component

- - - - -
+

List component

+

Input element

+ +
+

Bound inputs

+ + +
+ +@functions { + +string test = "hello"; + +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/MyInput.cshtml b/samples/PrerenderingApp.Client/MyInput.cshtml index 8fdd14ca2..4cd01ad20 100644 --- a/samples/PrerenderingApp.Client/MyInput.cshtml +++ b/samples/PrerenderingApp.Client/MyInput.cshtml @@ -1,10 +1 @@ -@using System.Diagnostics - - - - -@functions{ - - - -} \ No newline at end of file + diff --git a/samples/PrerenderingApp.Client/MyList.cshtml b/samples/PrerenderingApp.Client/MyList.cshtml index b46bcbc43..a9f44950c 100644 --- a/samples/PrerenderingApp.Client/MyList.cshtml +++ b/samples/PrerenderingApp.Client/MyList.cshtml @@ -7,7 +7,6 @@ int[] items = new[] {1, 2, 3, 4}; - protected override void OnInit() { base.OnInit(); diff --git a/samples/PrerenderingApp.Client/Program.cs b/samples/PrerenderingApp.Client/Program.cs index 38e13e7fe..3e80e32db 100644 --- a/samples/PrerenderingApp.Client/Program.cs +++ b/samples/PrerenderingApp.Client/Program.cs @@ -23,11 +23,5 @@ static void Main(string[] args) { new BrowserRenderer().AddComponent("app"); } - - /*static void Server(string[] args) - { - var renderer = new PreRenderer();//.AddComponent("app"); - renderer.DoStuff(); - }*/ } } diff --git a/samples/PrerenderingApp.Server/Program.cs b/samples/PrerenderingApp.Server/Program.cs index 7c7a5db43..d43624d3c 100644 --- a/samples/PrerenderingApp.Server/Program.cs +++ b/samples/PrerenderingApp.Server/Program.cs @@ -6,7 +6,6 @@ using System.Reflection; using System.Runtime.Loader; using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Blazor.Server.Rendering; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; @@ -16,28 +15,16 @@ public class Program { public static void Main(string[] args) { - var directory = Directory.GetCurrentDirectory(); - var currentDirectory = Environment.CurrentDirectory; - var codeBase = Assembly.GetEntryAssembly().CodeBase; - var location = Assembly.GetEntryAssembly().Location; AssemblyLoadContext.Default.Resolving += Default_Resolving; - - /*var prog = typeof(Client.Program); - var method = prog.GetMethod("Server", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - method.Invoke(null, new object[] { null });*/ - - var renderer = new PreRenderer();//.AddComponent("app"); - renderer.DoStuff(); - BuildWebHost(args).Run(); } - private static System.Reflection.Assembly Default_Resolving(AssemblyLoadContext arg1, System.Reflection.AssemblyName arg2) + private static Assembly Default_Resolving(AssemblyLoadContext context, AssemblyName assemblyName) { var location = Assembly.GetEntryAssembly().Location; var directoryName = Path.GetDirectoryName(location); - var assemblyPath = Path.Combine(directoryName, arg2.Name + ".dll"); - return arg1.LoadFromAssemblyPath(assemblyPath); + var assemblyPath = Path.Combine(directoryName, assemblyName.Name + ".dll"); + return context.LoadFromAssemblyPath(assemblyPath); } public static IWebHost BuildWebHost(string[] args) => diff --git a/samples/PrerenderingApp.Server/Startup.cs b/samples/PrerenderingApp.Server/Startup.cs index 34e49151b..4c99326ae 100644 --- a/samples/PrerenderingApp.Server/Startup.cs +++ b/samples/PrerenderingApp.Server/Startup.cs @@ -26,7 +26,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseDeveloperExceptionPage(); } - app.UseBlazorPrerendering(); + app.UseBlazorPrerendering(); } } } diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs index 0cc4091f7..644de38c3 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs @@ -6,7 +6,7 @@ public static class BlazorPrerenderingAppBuilderExtensions { public static void UseBlazorPrerendering(this IApplicationBuilder app) { - app.UseBlazor(c => c.UseBlazorPrerendering()); + app.UseBlazor(c => c.UseBlazorPrerendering()); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs index 4c3ff3a4a..0c702701f 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs @@ -1,24 +1,18 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; using AngleSharp; using AngleSharp.Html; using AngleSharp.Parser.Html; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SpaServices; -using Microsoft.AspNetCore.SpaServices.StaticFiles; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Blazor.Server.Rendering { public class BlazorPrerenderingMiddleware { - public static void Attach(ISpaBuilder spaBuilder) + public static void Attach(ISpaBuilder spaBuilder) { if (spaBuilder == null) throw new ArgumentNullException(nameof(spaBuilder)); @@ -34,6 +28,9 @@ public static void Attach(ISpaBuilder spaBuilder) applicationBuilder.Use((context, next) => { + var renderer = new PreRenderer(); + var pre = renderer.Render(); + var subpath = context.Request.Path; var fileInfo = fileOptions.FileProvider.GetFileInfo(subpath); if (fileInfo.Exists) @@ -48,9 +45,9 @@ public static void Attach(ISpaBuilder spaBuilder) { var html = reader.ReadToEnd(); - var content = Prerender(html); + var content = Prerender(html, pre); context.Response.ContentLength = content.Length; - using (var writer = new StreamWriter(context.Response.Body, Encoding.Default, 4096, leaveOpen: true)) + using (var writer = new StreamWriter(context.Response.Body)) { writer.Write(content); } @@ -63,7 +60,7 @@ public static void Attach(ISpaBuilder spaBuilder) }); } - private static string Prerender(string htmlTemplate) + private static string Prerender(string htmlTemplate, string pre) { // copied from IndexHtmlFileProvider.cs var resultBuilder = new StringBuilder(); @@ -71,7 +68,7 @@ private static string Prerender(string htmlTemplate) // Search for a tag of the form , and replace // it with the prerendered content var tokenizer = new HtmlTokenizer( - new TextSource(htmlTemplate), + new TextSource(htmlTemplate), HtmlEntityService.Resolver); var currentRangeStartPos = 0; var isInBlazorBootTag = false; @@ -99,7 +96,7 @@ private static string Prerender(string htmlTemplate) // Instead of emitting the source text for this special tag, emit a fully- // configured Blazor boot script tag - AppendScriptTagWithBootConfig(resultBuilder); + AppendScriptTagWithBootConfig(resultBuilder, pre); // Set a flag so we know not to emit anything else until the special // tag is closed @@ -130,9 +127,11 @@ private static bool IsBlazorBootTag(HtmlTagToken tag) => string.Equals(tag.Name, "app", StringComparison.Ordinal); private static void AppendScriptTagWithBootConfig( - StringBuilder resultBuilder) + StringBuilder resultBuilder, string pre) { - resultBuilder.AppendLine("

Hello Prerendering

"); + resultBuilder.AppendLine($@" +{pre} +"); } } diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs index d2d7fb4ff..a7d524515 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs @@ -4,9 +4,9 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { public static class BlazorPrerenderingSpaBuilderExtensions { - public static void UseBlazorPrerendering(this ISpaBuilder spa) + public static void UseBlazorPrerendering(this ISpaBuilder spa) { - BlazorPrerenderingMiddleware.Attach(spa); + BlazorPrerenderingMiddleware.Attach(spa); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs index a12c8d937..2bb22256a 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs @@ -19,29 +19,28 @@ public PreRenderer(IServiceProvider serviceProvider) : base(serviceProvider) { } - public void DoStuff() + private StringBuilder _sb; + + public string Render() { + _sb = new StringBuilder(); var component = InstantiateComponent(typeof(TComponent)); var componentId = AssignComponentId(component); component.SetParameters(ParameterCollection.Empty); + return _sb.ToString(); } protected override void UpdateDisplay(RenderBatch renderBatch) { - var sb = new StringBuilder(); - foreach (var u in renderBatch.UpdatedComponents) { - UpdateComponent(sb, renderBatch, u.ComponentId, u.Edits, renderBatch.ReferenceFrames); - + UpdateComponent(renderBatch, u.ComponentId, u.Edits, renderBatch.ReferenceFrames); } foreach (var componentID in renderBatch.DisposedComponentIDs) { DisposeComponent(componentID); } - - var s = sb.ToString(); } private void DisposeComponent(int componentId) @@ -52,7 +51,6 @@ private void DisposeComponent(int componentId) private IList handledComponents = new List(); private void UpdateComponent( - StringBuilder sb, RenderBatch renderBatch, int componentId, ArraySegment edits, @@ -60,11 +58,10 @@ private void UpdateComponent( { if (handledComponents.Contains(componentId)) return; handledComponents.Add(componentId); - ApplyEdit(sb, renderBatch, componentId, 0, edits, referenceFrames); + ApplyEdit(renderBatch, componentId, 0, edits, referenceFrames); } private void ApplyEdit( - StringBuilder sb, RenderBatch renderBatch, int componentId, int childIndex, @@ -82,7 +79,6 @@ private void ApplyEdit( case RenderTreeEditType.PrependFrame: var frame = referenceFrames.Array[edit.ReferenceFrameIndex]; InsertFrame( - sb, renderBatch, componentId, childIndexAtCurrentDepth + edit.SiblingIndex, @@ -109,7 +105,6 @@ private void ApplyEdit( } private int InsertFrame( - StringBuilder sb, RenderBatch renderBatch, int componentId, int childIndex, @@ -120,17 +115,16 @@ private int InsertFrame( switch (frame.FrameType) { case RenderTreeFrameType.Element: - InsertElement(sb, renderBatch, componentId, childIndex, frames, frame, frameIndex); + InsertElement(renderBatch, componentId, childIndex, frames, frame, frameIndex); return 1; case RenderTreeFrameType.Text: - InsertText(sb, childIndex, frame); + InsertText(childIndex, frame); return 1; case RenderTreeFrameType.Component: - InsertComponent(sb, renderBatch, childIndex, frame, frames); + InsertComponent(renderBatch, childIndex, frame, frames); return 1; case RenderTreeFrameType.Region: return InsertFrameRange( - sb, renderBatch, componentId, childIndex, @@ -144,29 +138,26 @@ private int InsertFrame( } private void InsertComponent( - StringBuilder sb, RenderBatch renderBatch, int childIndex, RenderTreeFrame frame, ArrayRange frames) { - sb.Append(""); + _sb.Append(""); var u = renderBatch.UpdatedComponents.Single(c => c.ComponentId == frame.ComponentId); - UpdateComponent(sb, renderBatch, u.ComponentId, u.Edits, frames); - sb.Append(""); + UpdateComponent(renderBatch, u.ComponentId, u.Edits, frames); + _sb.Append(""); } private void InsertText( - StringBuilder sb, int childIndex, RenderTreeFrame frame) { var textContent = frame.TextContent; - sb.Append(textContent); + _sb.Append(textContent); } private void InsertElement( - StringBuilder sb, RenderBatch renderBatch, int componentId, int childIndex, @@ -175,8 +166,8 @@ private void InsertElement( int frameIndex) { var tagName = frame.ElementName; - sb.Append("<"); - sb.Append(tagName); + _sb.Append("<"); + _sb.Append(tagName); var x = frameIndex + frame.ElementSubtreeLength; @@ -185,22 +176,22 @@ private void InsertElement( var dframe = frames.Array[di]; if (dframe.FrameType == RenderTreeFrameType.Attribute) { - ApplyAttribute(sb, componentId, dframe); + ApplyAttribute(componentId, dframe); } else { - sb.Append(">"); - InsertFrameRange(sb, renderBatch, componentId, 0, frames, di, x); - sb.Append(""); + InsertFrameRange(renderBatch, componentId, 0, frames, di, x); + _sb.Append(""); + _sb.Append(">"); } private int InsertFrameRange( - StringBuilder sb, RenderBatch renderBatch, int componentId, int childIndex, @@ -212,7 +203,7 @@ private int InsertFrameRange( for (var i = di; i < i1; i++) { var frame = frames.Array[i]; - var numAdded = InsertFrame(sb, renderBatch, componentId, childIndex, frames, frame, i); + var numAdded = InsertFrame(renderBatch, componentId, childIndex, frames, frame, i); childIndex += numAdded; var subTreeLength = frame.ElementSubtreeLength; @@ -225,15 +216,21 @@ private int InsertFrameRange( return (childIndex - org); } - private void ApplyAttribute(StringBuilder sb, int componentId, RenderTreeFrame dframe) + private static readonly string[] IgnoredAttributes = {"onclick", "onchange", "onkeypress"}; + + private void ApplyAttribute(int componentId, RenderTreeFrame dframe) { var attributeName = dframe.AttributeName; + + if (IgnoredAttributes.Contains(attributeName)) + return; + var value = dframe.AttributeValue; - sb.Append(" "); - sb.Append(attributeName); - sb.Append("=\""); - sb.Append(value); - sb.Append("\""); + _sb.Append(" "); + _sb.Append(attributeName); + _sb.Append("=\""); + _sb.Append(value); + _sb.Append("\""); } } } From 017a9fb9199e0181bfe24586bab732969a07d771 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Mon, 12 Mar 2018 22:47:30 +0100 Subject: [PATCH 06/11] allow to specify entry tag and services for prerendering --- samples/PrerenderingApp.Server/Startup.cs | 5 ++- .../BlazorPrerenderingAppBuilderExtensions.cs | 8 +++-- .../BlazorPrerenderingMiddleware.cs | 34 ++++++++++--------- .../BlazorPrerenderingSpaBuilderExtensions.cs | 8 +++-- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/samples/PrerenderingApp.Server/Startup.cs b/samples/PrerenderingApp.Server/Startup.cs index 4c99326ae..1074bd43d 100644 --- a/samples/PrerenderingApp.Server/Startup.cs +++ b/samples/PrerenderingApp.Server/Startup.cs @@ -26,7 +26,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseDeveloperExceptionPage(); } - app.UseBlazorPrerendering(); + app.UseBlazorPrerendering("app", configure => + { + // add services + }); } } } diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs index 644de38c3..ce80abae7 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs @@ -1,12 +1,14 @@ -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Blazor.Server.Rendering { public static class BlazorPrerenderingAppBuilderExtensions { - public static void UseBlazorPrerendering(this IApplicationBuilder app) + public static void UseBlazorPrerendering(this IApplicationBuilder app, string entryTagName, Action configure) { - app.UseBlazor(c => c.UseBlazorPrerendering()); + app.UseBlazor(c => c.UseBlazorPrerendering(entryTagName, configure)); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs index 0c702701f..89356e492 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs @@ -7,12 +7,13 @@ using AngleSharp.Parser.Html; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.SpaServices; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Blazor.Server.Rendering { public class BlazorPrerenderingMiddleware { - public static void Attach(ISpaBuilder spaBuilder) + public static void Attach(ISpaBuilder spaBuilder, string entryTagName, Action configure) { if (spaBuilder == null) throw new ArgumentNullException(nameof(spaBuilder)); @@ -26,10 +27,11 @@ public static void Attach(ISpaBuilder spaBuilder) return next(); }); + var col = new PreServiceProvider(configure); applicationBuilder.Use((context, next) => { - var renderer = new PreRenderer(); - var pre = renderer.Render(); + var renderer = new PreRenderer(col); + var content = renderer.Render(); var subpath = context.Request.Path; var fileInfo = fileOptions.FileProvider.GetFileInfo(subpath); @@ -45,11 +47,11 @@ public static void Attach(ISpaBuilder spaBuilder) { var html = reader.ReadToEnd(); - var content = Prerender(html, pre); - context.Response.ContentLength = content.Length; + var responseContent = Prerender(html, entryTagName, content); + context.Response.ContentLength = responseContent.Length; using (var writer = new StreamWriter(context.Response.Body)) { - writer.Write(content); + writer.Write(responseContent); } } @@ -60,7 +62,7 @@ public static void Attach(ISpaBuilder spaBuilder) }); } - private static string Prerender(string htmlTemplate, string pre) + private static string Prerender(string htmlTemplate, string entryTagName, string content) { // copied from IndexHtmlFileProvider.cs var resultBuilder = new StringBuilder(); @@ -88,7 +90,7 @@ private static string Prerender(string htmlTemplate, string pre) { // Only do anything special if this is a Blazor boot tag var tag = token.AsTag(); - if (IsBlazorBootTag(tag)) + if (IsEntryTag(tag, entryTagName)) { // First, emit the original source text prior to this special tag, since // we want that to be unchanged @@ -96,7 +98,7 @@ private static string Prerender(string htmlTemplate, string pre) // Instead of emitting the source text for this special tag, emit a fully- // configured Blazor boot script tag - AppendScriptTagWithBootConfig(resultBuilder, pre); + AppendContent(resultBuilder, entryTagName, content); // Set a flag so we know not to emit anything else until the special // tag is closed @@ -123,15 +125,15 @@ private static string Prerender(string htmlTemplate, string pre) } } - private static bool IsBlazorBootTag(HtmlTagToken tag) - => string.Equals(tag.Name, "app", StringComparison.Ordinal); + private static bool IsEntryTag(HtmlTagToken tag, string entryTagName) + => string.Equals(tag.Name, entryTagName, StringComparison.Ordinal); - private static void AppendScriptTagWithBootConfig( - StringBuilder resultBuilder, string pre) + private static void AppendContent( + StringBuilder resultBuilder, string tagName, string content) { - resultBuilder.AppendLine($@" -{pre} -"); + resultBuilder.AppendLine($@"<{tagName}> +{content} +"); } } diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs index a7d524515..a241bb1ba 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs @@ -1,12 +1,14 @@ -using Microsoft.AspNetCore.SpaServices; +using System; +using Microsoft.AspNetCore.SpaServices; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Blazor.Server.Rendering { public static class BlazorPrerenderingSpaBuilderExtensions { - public static void UseBlazorPrerendering(this ISpaBuilder spa) + public static void UseBlazorPrerendering(this ISpaBuilder spa, string entryTagName, Action configure) { - BlazorPrerenderingMiddleware.Attach(spa); + BlazorPrerenderingMiddleware.Attach(spa, entryTagName, configure); } } } \ No newline at end of file From 1650bfeee0f89cbf2d70c73bd82302130b81d34f Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Mon, 12 Mar 2018 23:10:51 +0100 Subject: [PATCH 07/11] add component consuming a service --- .../PrerenderingApp.Client/ConsumeService.cshtml | 14 ++++++++++++++ samples/PrerenderingApp.Client/Greeter.cs | 10 ++++++++++ samples/PrerenderingApp.Client/Home.cshtml | 3 +++ samples/PrerenderingApp.Client/Program.cs | 8 ++++++-- .../ServiceCollectionExtensions.cs | 12 ++++++++++++ samples/PrerenderingApp.Server/Startup.cs | 4 +++- 6 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 samples/PrerenderingApp.Client/ConsumeService.cshtml create mode 100644 samples/PrerenderingApp.Client/Greeter.cs create mode 100644 samples/PrerenderingApp.Client/ServiceCollectionExtensions.cs diff --git a/samples/PrerenderingApp.Client/ConsumeService.cshtml b/samples/PrerenderingApp.Client/ConsumeService.cshtml new file mode 100644 index 000000000..1eb068ec3 --- /dev/null +++ b/samples/PrerenderingApp.Client/ConsumeService.cshtml @@ -0,0 +1,14 @@ +@inject Greeter Greeter + +
+

@Greeter.Greet(name)

+
+ +
+
+ +@functions { + + string name = null; + +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/Greeter.cs b/samples/PrerenderingApp.Client/Greeter.cs new file mode 100644 index 000000000..40c39dcf5 --- /dev/null +++ b/samples/PrerenderingApp.Client/Greeter.cs @@ -0,0 +1,10 @@ +namespace PrerenderingApp.Client +{ + public class Greeter + { + public string Greet(string name) + { + return $"Hello {name}"; + } + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml index 13df57f27..506bf98ce 100644 --- a/samples/PrerenderingApp.Client/Home.cshtml +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -15,6 +15,9 @@ +

Consume Service

+ + @functions { string test = "hello"; diff --git a/samples/PrerenderingApp.Client/Program.cs b/samples/PrerenderingApp.Client/Program.cs index 3e80e32db..5f51d2ca4 100644 --- a/samples/PrerenderingApp.Client/Program.cs +++ b/samples/PrerenderingApp.Client/Program.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Blazor.Rendering; using Microsoft.AspNetCore.Blazor.RenderTree; using Microsoft.AspNetCore.Blazor.Services; -using Microsoft.Extensions.DependencyInjection; namespace PrerenderingApp.Client { @@ -21,7 +20,12 @@ public class Program { static void Main(string[] args) { - new BrowserRenderer().AddComponent("app"); + var serviceProvider = new BrowserServiceProvider(configure => + { + configure.AddSharedServices(); + }); + + new BrowserRenderer(serviceProvider).AddComponent("app"); } } } diff --git a/samples/PrerenderingApp.Client/ServiceCollectionExtensions.cs b/samples/PrerenderingApp.Client/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..01a5a21ab --- /dev/null +++ b/samples/PrerenderingApp.Client/ServiceCollectionExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace PrerenderingApp.Client +{ + public static class ServiceCollectionExtensions + { + public static void AddSharedServices(this IServiceCollection configure) + { + configure.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Server/Startup.cs b/samples/PrerenderingApp.Server/Startup.cs index 1074bd43d..32874460b 100644 --- a/samples/PrerenderingApp.Server/Startup.cs +++ b/samples/PrerenderingApp.Server/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; using Microsoft.AspNetCore.Blazor.Server.Rendering; +using PrerenderingApp.Client; namespace PrerenderingApp.Server { @@ -26,9 +27,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseDeveloperExceptionPage(); } - app.UseBlazorPrerendering("app", configure => + app.UseBlazorPrerendering("app", configure => { // add services + configure.AddSharedServices(); }); } } From 056ba54fcb6c462bca261a51f4b916235ddcad57 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Mon, 12 Mar 2018 23:39:24 +0100 Subject: [PATCH 08/11] use different implementations of service while prerendering to skip http call --- .../ClientWeatherService.cs | 22 ++++++++++ .../PrerenderingApp.Client/FetchData.cshtml | 43 +++++++++++++++++++ samples/PrerenderingApp.Client/Home.cshtml | 9 ++-- .../PrerenderingApp.Client/IWeatherService.cs | 10 +++++ samples/PrerenderingApp.Client/Program.cs | 12 +----- .../PrerenderingApp.Client/WeatherForecast.cs | 12 ++++++ .../Controller/SampleDataController.cs | 24 +++++++++++ .../PrerenderingApp.Server.csproj | 1 + .../ServerWeatherService.cs | 27 ++++++++++++ samples/PrerenderingApp.Server/Startup.cs | 26 ++++++++++- 10 files changed, 171 insertions(+), 15 deletions(-) create mode 100644 samples/PrerenderingApp.Client/ClientWeatherService.cs create mode 100644 samples/PrerenderingApp.Client/FetchData.cshtml create mode 100644 samples/PrerenderingApp.Client/IWeatherService.cs create mode 100644 samples/PrerenderingApp.Client/WeatherForecast.cs create mode 100644 samples/PrerenderingApp.Server/Controller/SampleDataController.cs create mode 100644 samples/PrerenderingApp.Server/ServerWeatherService.cs diff --git a/samples/PrerenderingApp.Client/ClientWeatherService.cs b/samples/PrerenderingApp.Client/ClientWeatherService.cs new file mode 100644 index 000000000..223b80cef --- /dev/null +++ b/samples/PrerenderingApp.Client/ClientWeatherService.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Blazor; + +namespace PrerenderingApp.Client +{ + public class ClientWeatherService : IWeatherService + { + private readonly HttpClient _httpClient; + + public ClientWeatherService(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task> GetForecast() + { + return await _httpClient.GetJsonAsync("/api/SampleData/WeatherForecasts"); + } + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/FetchData.cshtml b/samples/PrerenderingApp.Client/FetchData.cshtml new file mode 100644 index 000000000..2de2a92bf --- /dev/null +++ b/samples/PrerenderingApp.Client/FetchData.cshtml @@ -0,0 +1,43 @@ +@inject IWeatherService WeatherService + +

Weather forecast

+ +

This component demonstrates fetching data from the server.

+ +@if (forecasts == null) +{ +

Loading...

+} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
+} + +@functions { + WeatherForecast[] forecasts; + + protected override async Task OnInitAsync() + { + forecasts = (await WeatherService.GetForecast()).ToArray(); + } +} diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml index 506bf98ce..6400e1564 100644 --- a/samples/PrerenderingApp.Client/Home.cshtml +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -11,13 +11,16 @@

Bound inputs

- - + +
-

Consume Service

+

Consume same service on client and server

+

Consume different service on client and server

+ + @functions { string test = "hello"; diff --git a/samples/PrerenderingApp.Client/IWeatherService.cs b/samples/PrerenderingApp.Client/IWeatherService.cs new file mode 100644 index 000000000..d858fba53 --- /dev/null +++ b/samples/PrerenderingApp.Client/IWeatherService.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace PrerenderingApp.Client +{ + public interface IWeatherService + { + Task> GetForecast(); + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Client/Program.cs b/samples/PrerenderingApp.Client/Program.cs index 5f51d2ca4..c4eda8cde 100644 --- a/samples/PrerenderingApp.Client/Program.cs +++ b/samples/PrerenderingApp.Client/Program.cs @@ -1,18 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Linq; -using System.Collections.Generic; -using System.Net.Http; -using System.Text; -using Microsoft.AspNetCore.Blazor.Browser.Http; using Microsoft.AspNetCore.Blazor.Browser.Rendering; using Microsoft.AspNetCore.Blazor.Browser.Services; -using Microsoft.AspNetCore.Blazor.Components; -using Microsoft.AspNetCore.Blazor.Rendering; -using Microsoft.AspNetCore.Blazor.RenderTree; -using Microsoft.AspNetCore.Blazor.Services; +using Microsoft.Extensions.DependencyInjection; namespace PrerenderingApp.Client { @@ -23,6 +14,7 @@ static void Main(string[] args) var serviceProvider = new BrowserServiceProvider(configure => { configure.AddSharedServices(); + configure.AddSingleton(); }); new BrowserRenderer(serviceProvider).AddComponent("app"); diff --git a/samples/PrerenderingApp.Client/WeatherForecast.cs b/samples/PrerenderingApp.Client/WeatherForecast.cs new file mode 100644 index 000000000..93c5e9e01 --- /dev/null +++ b/samples/PrerenderingApp.Client/WeatherForecast.cs @@ -0,0 +1,12 @@ +using System; + +namespace PrerenderingApp.Client +{ + public class WeatherForecast + { + public DateTime Date { get; set; } + public int TemperatureC { get; set; } + public string Summary { get; set; } + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Server/Controller/SampleDataController.cs b/samples/PrerenderingApp.Server/Controller/SampleDataController.cs new file mode 100644 index 000000000..ae24757ab --- /dev/null +++ b/samples/PrerenderingApp.Server/Controller/SampleDataController.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using PrerenderingApp.Client; + +namespace PrerenderingApp.Server.Controller +{ + [Route("api/[controller]")] + public class SampleDataController : Microsoft.AspNetCore.Mvc.Controller + { + private readonly IWeatherService _weatherService; + + public SampleDataController(IWeatherService weatherService) + { + _weatherService = weatherService; + } + + [HttpGet("[action]")] + public async Task> WeatherForecasts() + { + return await _weatherService.GetForecast(); + } + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj b/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj index 0eafdf5e0..3bddaef03 100644 --- a/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj +++ b/samples/PrerenderingApp.Server/PrerenderingApp.Server.csproj @@ -6,6 +6,7 @@ + diff --git a/samples/PrerenderingApp.Server/ServerWeatherService.cs b/samples/PrerenderingApp.Server/ServerWeatherService.cs new file mode 100644 index 000000000..61f5c0c56 --- /dev/null +++ b/samples/PrerenderingApp.Server/ServerWeatherService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using PrerenderingApp.Client; + +namespace PrerenderingApp.Server +{ + public class ServerWeatherService : IWeatherService + { + private static string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + public Task> GetForecast() + { + var rng = new Random(); + return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = rng.Next(-20, 55), + Summary = Summaries[rng.Next(Summaries.Length)] + })); + } + } +} \ No newline at end of file diff --git a/samples/PrerenderingApp.Server/Startup.cs b/samples/PrerenderingApp.Server/Startup.cs index 32874460b..9e1084bcf 100644 --- a/samples/PrerenderingApp.Server/Startup.cs +++ b/samples/PrerenderingApp.Server/Startup.cs @@ -1,12 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Linq; +using System.Net.Mime; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using System.Threading.Tasks; using Microsoft.AspNetCore.Blazor.Server.Rendering; +using Microsoft.AspNetCore.ResponseCompression; +using Newtonsoft.Json.Serialization; using PrerenderingApp.Client; namespace PrerenderingApp.Server @@ -17,20 +19,40 @@ public class Startup // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { + services.AddMvc().AddJsonOptions(options => + { + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + }); + + services.AddResponseCompression(options => + { + options.MimeTypes = ResponseCompressionDefaults.MimeTypes + .Concat(new[] { MediaTypeNames.Application.Octet }); + }); + + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { + app.UseResponseCompression(); + if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } + app.UseMvc(routes => + { + routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}"); + }); + app.UseBlazorPrerendering("app", configure => { // add services configure.AddSharedServices(); + configure.AddSingleton(); }); } } From 419cb4994b10f449cdfb447c302b15b81680d7e6 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Mon, 7 May 2018 16:46:15 +0200 Subject: [PATCH 09/11] pre rendering demo --- samples/PrerenderingApp.Client/Home.cshtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml index 6400e1564..12ade797c 100644 --- a/samples/PrerenderingApp.Client/Home.cshtml +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -1,6 +1,6 @@ 

Prerendering Sample

-

Input component

+@*

Input component

List component

@@ -16,13 +16,13 @@

Consume same service on client and server

- +*@

Consume different service on client and server

@functions { -string test = "hello"; + //string test = "hello"; } \ No newline at end of file From 590b4e0b06ab4bf5752bbad6af6f3900cd4b938d Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Mon, 7 May 2018 17:06:14 +0200 Subject: [PATCH 10/11] fix after rebase --- Blazor.sln | 16 +++++++- .../ConsumeService.cshtml | 2 +- samples/PrerenderingApp.Client/Home.cshtml | 2 +- .../PrerenderingApp.Client.csproj | 16 +++++--- .../BlazorPrerenderingAppBuilderExtensions.cs | 10 +++++ .../BlazorPrerenderingMiddleware.cs | 10 +++++ .../BlazorPrerenderingSpaBuilderExtensions.cs | 10 +++++ ....AspNetCore.Blazor.Server.Rendering.csproj | 8 +++- .../PreRenderer.cs | 19 +++++++++ .../PreServiceProvider.cs | 3 ++ .../PreUriHelper.cs | 41 ++++++++++++++++++- .../BlazorOptions.cs | 2 +- 12 files changed, 125 insertions(+), 14 deletions(-) diff --git a/Blazor.sln b/Blazor.sln index e274ec045..a7fc9fe7a 100644 --- a/Blazor.sln +++ b/Blazor.sln @@ -77,7 +77,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorHosted-CSharp.Client" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorHosted-CSharp.Server", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorHosted-CSharp\BlazorHosted-CSharp.Server\BlazorHosted-CSharp.Server.csproj", "{78ED9932-0912-4F36-8F82-33DE850E7A33}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorHosted-CSharp.Shared", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorHosted-CSharp\BlazorHosted-CSharp.Shared\BlazorHosted-CSharp.Shared.csproj", "{F3E02B21-1127-431A-B832-0E53CB72097B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorHosted-CSharp.Shared", "src\Microsoft.AspNetCore.Blazor.Templates\content\BlazorHosted-CSharp\BlazorHosted-CSharp.Shared\BlazorHosted-CSharp.Shared.csproj", "{F3E02B21-1127-431A-B832-0E53CB72097B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Prerendering", "Prerendering", "{0A6A1E7D-2236-4695-A5B1-0A82EEED0B6C}" EndProject @@ -299,19 +299,31 @@ Global {F3E02B21-1127-431A-B832-0E53CB72097B}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU {F3E02B21-1127-431A-B832-0E53CB72097B}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3E02B21-1127-431A-B832-0E53CB72097B}.Release|Any CPU.Build.0 = Release|Any CPU + {F3E02B21-1127-431A-B832-0E53CB72097B}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU {9C424433-8AA6-452B-BA9E-01ACD2852176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9C424433-8AA6-452B-BA9E-01ACD2852176}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU {9C424433-8AA6-452B-BA9E-01ACD2852176}.Release|Any CPU.ActiveCfg = Release|Any CPU {9C424433-8AA6-452B-BA9E-01ACD2852176}.Release|Any CPU.Build.0 = Release|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU + {9C424433-8AA6-452B-BA9E-01ACD2852176}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.Release|Any CPU.Build.0 = Release|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU + {034F0B11-DBA2-44A9-932E-BFCD94DB5F7D}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.Release|Any CPU.Build.0 = Release|Any CPU - {F3E02B21-1127-431A-B832-0E53CB72097B}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU + {A61788D9-3764-4BC5-A5BB-118D4A10BBEB}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU {FF25111E-5A3E-48A3-96D8-08A2C5A2A91C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF25111E-5A3E-48A3-96D8-08A2C5A2A91C}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF25111E-5A3E-48A3-96D8-08A2C5A2A91C}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/samples/PrerenderingApp.Client/ConsumeService.cshtml b/samples/PrerenderingApp.Client/ConsumeService.cshtml index 1eb068ec3..1dc7bec61 100644 --- a/samples/PrerenderingApp.Client/ConsumeService.cshtml +++ b/samples/PrerenderingApp.Client/ConsumeService.cshtml @@ -3,7 +3,7 @@

@Greeter.Greet(name)

- +
diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml index 12ade797c..68387baa4 100644 --- a/samples/PrerenderingApp.Client/Home.cshtml +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -19,7 +19,7 @@ *@

Consume different service on client and server

- + @functions { diff --git a/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj b/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj index a64eebc99..69213ce48 100644 --- a/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj +++ b/samples/PrerenderingApp.Client/PrerenderingApp.Client.csproj @@ -1,15 +1,19 @@ - + netstandard2.0 - + Exe - - + + false + + - - + + + + diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs index ce80abae7..37dedec7d 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingAppBuilderExtensions.cs @@ -4,8 +4,18 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { + /// + /// + /// public static class BlazorPrerenderingAppBuilderExtensions { + /// + /// + /// + /// + /// + /// + /// public static void UseBlazorPrerendering(this IApplicationBuilder app, string entryTagName, Action configure) { app.UseBlazor(c => c.UseBlazorPrerendering(entryTagName, configure)); diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs index 89356e492..80c797070 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingMiddleware.cs @@ -11,8 +11,18 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { + /// + /// + /// public class BlazorPrerenderingMiddleware { + /// + /// + /// + /// + /// + /// + /// public static void Attach(ISpaBuilder spaBuilder, string entryTagName, Action configure) { if (spaBuilder == null) diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs index a241bb1ba..9f7ad3bd0 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/BlazorPrerenderingSpaBuilderExtensions.cs @@ -4,8 +4,18 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { + /// + /// + /// public static class BlazorPrerenderingSpaBuilderExtensions { + /// + /// + /// + /// + /// + /// + /// public static void UseBlazorPrerendering(this ISpaBuilder spa, string entryTagName, Action configure) { BlazorPrerenderingMiddleware.Attach(spa, entryTagName, configure); diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj index db6e7fece..fb424d2b6 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/Microsoft.AspNetCore.Blazor.Server.Rendering.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.0 @@ -14,7 +14,7 @@
- + + + + diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs index 2bb22256a..b2d5f5e2f 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreRenderer.cs @@ -8,19 +8,34 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { + /// + /// + /// public class PreRenderer : Renderer { + /// + /// + /// public PreRenderer() : this(new PreServiceProvider()) { } + /// + /// + /// + /// public PreRenderer(IServiceProvider serviceProvider) : base(serviceProvider) { } private StringBuilder _sb; + /// + /// + /// + /// + /// public string Render() { _sb = new StringBuilder(); @@ -30,6 +45,10 @@ public string Render() return _sb.ToString(); } + /// + /// + /// + /// protected override void UpdateDisplay(RenderBatch renderBatch) { foreach (var u in renderBatch.UpdatedComponents) diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs index 234e56f5a..b24433526 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreServiceProvider.cs @@ -5,6 +5,9 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { + /// + /// + /// public class PreServiceProvider : IServiceProvider { private readonly IServiceProvider _underlyingProvider; diff --git a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs index 6ed2bf2d1..644094505 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server.Rendering/PreUriHelper.cs @@ -3,32 +3,71 @@ namespace Microsoft.AspNetCore.Blazor.Server.Rendering { + /// + /// + /// public class PreUriHelper : IUriHelper { + /// + /// + /// + /// public string GetAbsoluteUri() { throw new NotImplementedException(); } + /// + /// + /// public event EventHandler OnLocationChanged; + + /// + /// + /// + /// + /// public Uri ToAbsoluteUri(string href) { throw new NotImplementedException(); } + /// + /// + /// + /// public string GetBaseUriPrefix() { return "http://localhost:56484/"; } + /// + /// + /// + /// + /// + /// public string ToBaseRelativePath(string baseUriPrefix, string locationAbsolute) { throw new NotImplementedException(); } - + + /// + /// + /// + /// protected virtual void OnOnLocationChanged(string e) { OnLocationChanged?.Invoke(this, e); } + + /// + /// + /// + /// + public void NavigateTo(string uri) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Blazor.Server/BlazorOptions.cs b/src/Microsoft.AspNetCore.Blazor.Server/BlazorOptions.cs index e7cf9c88d..06518aa7a 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server/BlazorOptions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server/BlazorOptions.cs @@ -4,7 +4,7 @@ namespace Microsoft.AspNetCore.Builder { /// - /// Provides configuration options to the + /// Provides configuration options to the /// middleware. /// public class BlazorOptions From 900db1264b4a4e62857b4f5d88c18fa7a33c1bd6 Mon Sep 17 00:00:00 2001 From: Florian Dohrendorf Date: Mon, 7 May 2018 17:24:34 +0200 Subject: [PATCH 11/11] enable other components --- samples/PrerenderingApp.Client/Home.cshtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/samples/PrerenderingApp.Client/Home.cshtml b/samples/PrerenderingApp.Client/Home.cshtml index 68387baa4..d5578e80c 100644 --- a/samples/PrerenderingApp.Client/Home.cshtml +++ b/samples/PrerenderingApp.Client/Home.cshtml @@ -1,28 +1,28 @@ 

Prerendering Sample

-@*

Input component

- +

Input component

+

List component

- +

Input element

Bound inputs

- - + +

Consume same service on client and server

-*@ +

Consume different service on client and server

@functions { - //string test = "hello"; + string test = "hello"; } \ No newline at end of file