From fd12d0908e88b91fb8d7ccee3eecb4b42ef36203 Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Mon, 23 Aug 2021 12:54:26 +0100 Subject: [PATCH 1/8] Support for implementing @section, @RenderSection --- ExampleAppCore/LayoutAndSections.cs | 179 ++++++++++++++++++ ExampleAppCore/RazorEngineCoreExtensions.cs | 23 +++ RazorEngineCore/RazorEngine.cs | 1 + .../RazorEngineCompilationOptions.cs | 3 + RazorEngineCore/RazorEngineTemplateBase.cs | 13 +- 5 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 ExampleAppCore/LayoutAndSections.cs create mode 100644 ExampleAppCore/RazorEngineCoreExtensions.cs diff --git a/ExampleAppCore/LayoutAndSections.cs b/ExampleAppCore/LayoutAndSections.cs new file mode 100644 index 0000000..05827cf --- /dev/null +++ b/ExampleAppCore/LayoutAndSections.cs @@ -0,0 +1,179 @@ +using Microsoft.AspNetCore.Razor.Language.Extensions; +using RazorEngineCore; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + + +namespace ExampleApp +{ + + public static class LayoutAndSections + { + /// + /// Provides an example of using @section and @RenderSection, based on the layout implementation + /// at https://github.com/adoconnection/RazorEngineCore/wiki/@Include-and-@Layout + /// + public static void Test() + { + + string template = @" + @{ + Layout = ""MyLayout""; + } + +

@Model.Title

+ + @Include(""outer"", Model) + + @section mysection + { + This is in a section + } + "; + + IDictionary parts = new Dictionary() + { + {"MyLayout", @" + LAYOUT HEADER + @RenderBody() + @RenderSection(""mysection"") + LAYOUT FOOTER + "}, + {"outer", "This is Outer include, <@Model.Title>, @Include(\"inner\")"}, + {"inner", "This is Inner include"} + }; + + var razorEngine = new RazorEngine(); + + MyCompiledTemplate compiledTemplate = razorEngine.Compile(template, parts, (builder) => + { + builder.Options.ProjectEngineBuilderAction = (x) => SectionDirective.Register(x); + }); + + string result = compiledTemplate.Run(new { Title = "Hello" }); + + Console.WriteLine(result); + Console.ReadKey(); + } + } + + + public class MyTemplateBase : RazorEngineTemplateBase + { + public Func IncludeCallback { get; set; } + public Func RenderBodyCallback { get; set; } + public string Layout { get; set; } + + public string Include(string key, object model = null) + { + return this.IncludeCallback(key, model); + } + + public string RenderBody() + { + return this.RenderBodyCallback(); + } + + public Dictionary Sections = new Dictionary(); + + public void DefineSection(string name, Action a) + { + Debug.WriteLine("DefineSection " + name); + var sb = new StringBuilder(); + BeginCapture(sb); + a(); + EndCapture(); + string content = sb.ToString(); + Sections.Add(name, content); + Debug.WriteLine("Section content:"); + Debug.WriteLine(content); + } + + public string RenderSection(string name, bool required = false) + { + if (Sections.TryGetValue(name, out var content)) + return content; + else if (required) + throw new Exception("Required section not found: " + name); + return string.Empty; + } + } + + + public class MyCompiledTemplate + { + private readonly IRazorEngineCompiledTemplate compiledTemplate; + private readonly Dictionary> compiledParts; + + public MyCompiledTemplate(IRazorEngineCompiledTemplate compiledTemplate, Dictionary> compiledParts) + { + this.compiledTemplate = compiledTemplate; + this.compiledParts = compiledParts; + } + + public string Run(object model) + { + return this.Run(this.compiledTemplate, model); + } + + public string Run(IRazorEngineCompiledTemplate template, object model) + { + MyTemplateBase templateReference = null; + + string result = template.Run(instance => + { + if (!(model is AnonymousTypeWrapper)) + { + model = new AnonymousTypeWrapper(model); + } + + instance.Model = model; + instance.IncludeCallback = (key, includeModel) => this.Run(this.compiledParts[key], includeModel); + + templateReference = instance; + }); + + if (templateReference.Layout == null) + { + return result; + } + + return this.compiledParts[templateReference.Layout].Run(instance => + { + if (!(model is AnonymousTypeWrapper)) + { + model = new AnonymousTypeWrapper(model); + } + instance.Sections = templateReference.Sections; + instance.Model = model; + instance.IncludeCallback = (key, includeModel) => this.Run(this.compiledParts[key], includeModel); + instance.RenderBodyCallback = () => result; + }); + } + + public void Save() + { + /* + TODO + + this.compiledTemplate.SaveToFile(); + this.compiledTemplate.SaveToStream(); + + foreach (var compiledPart in this.compiledParts) + { + compiledPart.Value.SaveToFile(); + compiledPart.Value.SaveToStream(); + } + */ + } + + public void Load() + { + // TODO + } + } + +} diff --git a/ExampleAppCore/RazorEngineCoreExtensions.cs b/ExampleAppCore/RazorEngineCoreExtensions.cs new file mode 100644 index 0000000..cf5a06c --- /dev/null +++ b/ExampleAppCore/RazorEngineCoreExtensions.cs @@ -0,0 +1,23 @@ +using RazorEngineCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ExampleApp +{ + public static class RazorEngineCoreExtensions + { + public static MyCompiledTemplate Compile(this RazorEngine razorEngine, string template, IDictionary parts, + Action builderAction = null) + { + return new MyCompiledTemplate( + razorEngine.Compile(template, builderAction), + parts.ToDictionary( + k => k.Key, + v => razorEngine.Compile(v.Value))); + } + + } + +} diff --git a/RazorEngineCore/RazorEngine.cs b/RazorEngineCore/RazorEngine.cs index 6d83cc6..1cd6fb3 100644 --- a/RazorEngineCore/RazorEngine.cs +++ b/RazorEngineCore/RazorEngine.cs @@ -60,6 +60,7 @@ private MemoryStream CreateAndCompileToStream(string templateSource, RazorEngine (builder) => { builder.SetNamespace(options.TemplateNamespace); + options.ProjectEngineBuilderAction?.Invoke(builder); }); string fileName = Path.GetRandomFileName(); diff --git a/RazorEngineCore/RazorEngineCompilationOptions.cs b/RazorEngineCore/RazorEngineCompilationOptions.cs index c058e60..e30b630 100644 --- a/RazorEngineCore/RazorEngineCompilationOptions.cs +++ b/RazorEngineCore/RazorEngineCompilationOptions.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; using System; +using Microsoft.AspNetCore.Razor.Language; namespace RazorEngineCore { @@ -21,6 +22,8 @@ public class RazorEngineCompilationOptions "System.Collections.Generic" }; + public Action ProjectEngineBuilderAction { get; set; } + public RazorEngineCompilationOptions() { bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); diff --git a/RazorEngineCore/RazorEngineTemplateBase.cs b/RazorEngineCore/RazorEngineTemplateBase.cs index b54e570..dcbb524 100644 --- a/RazorEngineCore/RazorEngineTemplateBase.cs +++ b/RazorEngineCore/RazorEngineTemplateBase.cs @@ -5,7 +5,18 @@ namespace RazorEngineCore { public abstract class RazorEngineTemplateBase : IRazorEngineTemplate { - private readonly StringBuilder stringBuilder = new StringBuilder(); + private readonly StringBuilder _stringBuilder = new StringBuilder(); + private StringBuilder _captureStringBuilder; + private StringBuilder stringBuilder => _captureStringBuilder ?? _stringBuilder; + + protected void BeginCapture(StringBuilder sb) + { + _captureStringBuilder = sb; + } + protected void EndCapture() + { + _captureStringBuilder = null; + } private string attributeSuffix = null; From 5d7d4bc102636fcfbfadc14d1460b83630afbaa8 Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Mon, 23 Aug 2021 13:45:06 +0100 Subject: [PATCH 2/8] Cleanup --- ExampleAppCore/LayoutAndSections.cs | 9 +++++---- RazorEngineCore/RazorEngineTemplateBase.cs | 15 +++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ExampleAppCore/LayoutAndSections.cs b/ExampleAppCore/LayoutAndSections.cs index 05827cf..545125f 100644 --- a/ExampleAppCore/LayoutAndSections.cs +++ b/ExampleAppCore/LayoutAndSections.cs @@ -32,6 +32,7 @@ @section mysection { This is in a section } + "; IDictionary parts = new Dictionary() @@ -39,7 +40,9 @@ This is in a section {"MyLayout", @" LAYOUT HEADER @RenderBody() + Before section @RenderSection(""mysection"") + After section LAYOUT FOOTER "}, {"outer", "This is Outer include, <@Model.Title>, @Include(\"inner\")"}, @@ -82,11 +85,9 @@ public string RenderBody() public void DefineSection(string name, Action a) { Debug.WriteLine("DefineSection " + name); - var sb = new StringBuilder(); - BeginCapture(sb); + BeginCapture(); a(); - EndCapture(); - string content = sb.ToString(); + string content = EndCapture(); Sections.Add(name, content); Debug.WriteLine("Section content:"); Debug.WriteLine(content); diff --git a/RazorEngineCore/RazorEngineTemplateBase.cs b/RazorEngineCore/RazorEngineTemplateBase.cs index dcbb524..dd432cb 100644 --- a/RazorEngineCore/RazorEngineTemplateBase.cs +++ b/RazorEngineCore/RazorEngineTemplateBase.cs @@ -1,4 +1,5 @@ -using System.Text; +using System; +using System.Text; using System.Threading.Tasks; namespace RazorEngineCore @@ -9,13 +10,19 @@ public abstract class RazorEngineTemplateBase : IRazorEngineTemplate private StringBuilder _captureStringBuilder; private StringBuilder stringBuilder => _captureStringBuilder ?? _stringBuilder; - protected void BeginCapture(StringBuilder sb) + protected void BeginCapture() { - _captureStringBuilder = sb; + if (_captureStringBuilder != null) + throw new InvalidOperationException("Already capturing"); + _captureStringBuilder = new StringBuilder(); } - protected void EndCapture() + protected string EndCapture() { + if (_captureStringBuilder == null) + throw new InvalidOperationException("Not capturing"); + string result = _captureStringBuilder.ToString(); _captureStringBuilder = null; + return result; } private string attributeSuffix = null; From 9aeaef7efadf511960e42a8c0e817491defa7486 Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Mon, 6 Feb 2023 17:14:04 +0000 Subject: [PATCH 3/8] object creation fix --- RazorEngineCore/RazorEngineCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RazorEngineCore/RazorEngineCore.csproj b/RazorEngineCore/RazorEngineCore.csproj index b145bdc..122f97a 100644 --- a/RazorEngineCore/RazorEngineCore.csproj +++ b/RazorEngineCore/RazorEngineCore.csproj @@ -21,6 +21,6 @@ - + From 8f4cab37241bbb3dd08195cd3fc7aa5ff26d97da Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Sat, 4 Nov 2023 11:04:48 +0000 Subject: [PATCH 4/8] move data classes to library; api prep --- RazorEngineCore/RazorEngineCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RazorEngineCore/RazorEngineCore.csproj b/RazorEngineCore/RazorEngineCore.csproj index 122f97a..dae89ae 100644 --- a/RazorEngineCore/RazorEngineCore.csproj +++ b/RazorEngineCore/RazorEngineCore.csproj @@ -1,6 +1,6 @@  - net6.0;net5.0;netstandard2.0 + net6.0;netstandard2.0 true 2022.8.1 Alexander Selishchev, Simon Mourier, William David Cossey, Benjamin Smith, Dag H. Baardsen, krmr, jddj007-hydra From 19cfd6dec00334ba9c1dee4ca2abdfd90f030a80 Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Sat, 4 Nov 2023 11:12:54 +0000 Subject: [PATCH 5/8] remove net50 tests --- RazorEngineCore.Tests/RazorEngineCore.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj b/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj index 636858a..dd12b7c 100644 --- a/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj +++ b/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net472;net5.0;net6.0 + netcoreapp3.1;net472;net6.0 false From 2f77205633e3b8e8729f92a35b9fb3cf9e86e752 Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Sat, 4 Nov 2023 11:18:22 +0000 Subject: [PATCH 6/8] remove core 3.1 --- RazorEngineCore.Tests/RazorEngineCore.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj b/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj index dd12b7c..1ca2f7b 100644 --- a/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj +++ b/RazorEngineCore.Tests/RazorEngineCore.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net472;net6.0 + net472;net6.0 false From a91c44ca99e3b6bf7f12c63d8fcece9aafb6cb6f Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Tue, 19 Mar 2024 19:54:08 +0000 Subject: [PATCH 7/8] code cleanup; dependency update; dashboard fixes --- RazorEngineCore/RazorEngineCore.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RazorEngineCore/RazorEngineCore.csproj b/RazorEngineCore/RazorEngineCore.csproj index dae89ae..ce85afd 100644 --- a/RazorEngineCore/RazorEngineCore.csproj +++ b/RazorEngineCore/RazorEngineCore.csproj @@ -20,7 +20,7 @@ true - - + + From af0b7847551b44f7caac6b7fe84e145c56a29f2f Mon Sep 17 00:00:00 2001 From: Kevin Flanagan Date: Sun, 21 Apr 2024 21:21:30 +0100 Subject: [PATCH 8/8] .net7 upgrade --- RazorEngineCore/RazorEngineCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RazorEngineCore/RazorEngineCore.csproj b/RazorEngineCore/RazorEngineCore.csproj index ce85afd..a7722cd 100644 --- a/RazorEngineCore/RazorEngineCore.csproj +++ b/RazorEngineCore/RazorEngineCore.csproj @@ -1,6 +1,6 @@  - net6.0;netstandard2.0 + net7.0;netstandard2.0 true 2022.8.1 Alexander Selishchev, Simon Mourier, William David Cossey, Benjamin Smith, Dag H. Baardsen, krmr, jddj007-hydra