diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 327bb239..42a0f88d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -23,23 +23,17 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Setup .NET 2.1
- uses: actions/setup-dotnet@v1
- with:
- dotnet-version: 2.1.*
- - name: Setup .NET 3.1
- uses: actions/setup-dotnet@v1
- with:
- dotnet-version: 3.1.*
- - name: Setup .NET 5.0
- uses: actions/setup-dotnet@v1
- with:
- dotnet-version: 5.0.*
- - name: Setup .NET 6.0
+
+ - name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 6.0.*
+ dotnet-version: |
+ 3.1.x
+ 5.0.x
+ 6.0.x
+
- name: Test
run: dotnet test --configuration Release
+
- name: Test - Compiled
run: dotnet test --configuration Release /p:Compiled=true
diff --git a/Fluid.MvcViewEngine/FluidMvcViewOptions.cs b/Fluid.MvcViewEngine/FluidMvcViewOptions.cs
index 7c1fe152..2dde5478 100644
--- a/Fluid.MvcViewEngine/FluidMvcViewOptions.cs
+++ b/Fluid.MvcViewEngine/FluidMvcViewOptions.cs
@@ -1,9 +1,16 @@
using Fluid.ViewEngine;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using System.Threading.Tasks;
namespace Fluid.MvcViewEngine
{
public class FluidMvcViewOptions : FluidViewEngineOptions
{
- // Placeholder for future options specific to the MVC view engine
+ public delegate ValueTask RenderingMvcViewDelegate(string path, ViewContext viewContext, TemplateContext context);
+
+ ///
+ /// Gets or sets the delegate to execute when a view is rendered.
+ ///
+ public new RenderingMvcViewDelegate RenderingViewAsync { get; set; }
}
}
diff --git a/Fluid.MvcViewEngine/FluidRendering.cs b/Fluid.MvcViewEngine/FluidRendering.cs
index f969a6c2..29e97341 100644
--- a/Fluid.MvcViewEngine/FluidRendering.cs
+++ b/Fluid.MvcViewEngine/FluidRendering.cs
@@ -1,6 +1,7 @@
using Fluid.ViewEngine;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Options;
using System.IO;
@@ -32,14 +33,19 @@ public FluidRendering(
}
private readonly IWebHostEnvironment _hostingEnvironment;
- private readonly FluidViewEngineOptions _options;
+ private readonly FluidMvcViewOptions _options;
- public async Task RenderAsync(TextWriter writer, string path, object model, ViewDataDictionary viewData, ModelStateDictionary modelState)
+ public async Task RenderAsync(TextWriter writer, string path, ViewContext viewContext)
{
var context = new TemplateContext(_options.TemplateOptions);
- context.SetValue("ViewData", viewData);
- context.SetValue("ModelState", modelState);
- context.SetValue("Model", model);
+ context.SetValue("ViewData", viewContext.ViewData);
+ context.SetValue("ModelState", viewContext.ModelState);
+ context.SetValue("Model", viewContext.ViewData.Model);
+
+ if (_options.RenderingViewAsync != null)
+ {
+ await _options.RenderingViewAsync.Invoke(path, viewContext, context);
+ }
await _fluidViewRenderer.RenderViewAsync(writer, path, context);
}
diff --git a/Fluid.MvcViewEngine/FluidTagHelper.cs b/Fluid.MvcViewEngine/FluidTagHelper.cs
index 0c89cd91..170a84b0 100644
--- a/Fluid.MvcViewEngine/FluidTagHelper.cs
+++ b/Fluid.MvcViewEngine/FluidTagHelper.cs
@@ -1,5 +1,7 @@
using System.IO;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Fluid.MvcViewEngine
@@ -14,6 +16,10 @@ public FluidTagHelper(FluidRendering fluidRendering)
_fluidRendering = fluidRendering;
}
+ [HtmlAttributeNotBound]
+ [ViewContext]
+ public ViewContext ViewContext { get; set; }
+
[HtmlAttributeName("model")]
public object Model { get; set; }
@@ -31,7 +37,7 @@ static async Task Awaited(TagHelperOutput o, StringWriter sw, Task t)
using (var sw = new StringWriter())
{
- var task = _fluidRendering.RenderAsync(sw, View, Model, null, null);
+ var task = _fluidRendering.RenderAsync(sw, View, ViewContext);
if (task.IsCompletedSuccessfully)
{
diff --git a/Fluid.MvcViewEngine/FluidView.cs b/Fluid.MvcViewEngine/FluidView.cs
index 7345016c..d4290ed8 100644
--- a/Fluid.MvcViewEngine/FluidView.cs
+++ b/Fluid.MvcViewEngine/FluidView.cs
@@ -25,7 +25,7 @@ public string Path
public async Task RenderAsync(ViewContext context)
{
- await _fluidRendering.RenderAsync(context.Writer, Path, context.ViewData.Model, context.ViewData, context.ModelState);
+ await _fluidRendering.RenderAsync(context.Writer, Path, context);
}
}
}
diff --git a/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs b/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
index aa141d4e..e47d4267 100644
--- a/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
+++ b/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
@@ -225,10 +225,25 @@ public async Task ShouldNotIncludeViewStartInLayout()
var sw = new StringWriter();
await _renderer.RenderViewAsync(sw, "Index.liquid", new TemplateContext());
await sw.FlushAsync();
-
Assert.Equal("[Layout][ViewStart][View]", sw.ToString());
}
+ [Fact]
+ public async Task ShouldInvokeRenderingViewAsync()
+ {
+ _options.RenderingViewAsync = (view, context) => { context.SetValue("custom", "hello"); return default; };
+
+ _mockFileProvider.Add("Views/Index.liquid", "{{ custom }}");
+
+ var sw = new StringWriter();
+ await _renderer.RenderViewAsync(sw, "Index.liquid", new TemplateContext());
+ await sw.FlushAsync();
+
+ _options.RenderingViewAsync = null;
+
+ Assert.Equal("hello", sw.ToString());
+ }
+
[Fact]
public async Task ShouldApplyViewStartLayoutsRecursively()
{
diff --git a/Fluid.ViewEngine/FluidViewEngineOptions.cs b/Fluid.ViewEngine/FluidViewEngineOptions.cs
index 4cd62ac8..2a2122b4 100644
--- a/Fluid.ViewEngine/FluidViewEngineOptions.cs
+++ b/Fluid.ViewEngine/FluidViewEngineOptions.cs
@@ -1,6 +1,8 @@
using Microsoft.Extensions.FileProviders;
+using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
+using System.Threading.Tasks;
namespace Fluid.ViewEngine
{
@@ -62,5 +64,15 @@ public class FluidViewEngineOptions
/// Gets or sets whether files should be reloaded automatically when changed. Default is true
;
///
public bool TrackFileChanges { get; set; } = true;
+
+ ///
+ /// Represents the method that will handle the view rendering event.
+ ///
+ public delegate ValueTask RenderingViewDelegate(string path, TemplateContext context);
+
+ ///
+ /// Gets or sets the delegate to execute when a view is rendered.
+ ///
+ public RenderingViewDelegate RenderingViewAsync { get; set; }
}
}
diff --git a/Fluid.ViewEngine/FluidViewRenderer.cs b/Fluid.ViewEngine/FluidViewRenderer.cs
index 8123712a..e2e87c39 100644
--- a/Fluid.ViewEngine/FluidViewRenderer.cs
+++ b/Fluid.ViewEngine/FluidViewRenderer.cs
@@ -43,6 +43,11 @@ public virtual async Task RenderViewAsync(TextWriter writer, string relativePath
var template = await GetFluidTemplateAsync(relativePath, _fluidViewEngineOptions.ViewsFileProvider, true);
+ if (_fluidViewEngineOptions.RenderingViewAsync != null)
+ {
+ await _fluidViewEngineOptions.RenderingViewAsync.Invoke(relativePath, context);
+ }
+
// The body is rendered and buffered before the Layout since it can contain fragments
// that need to be rendered as part of the Layout.
// Also the body or its _ViewStarts might contain a Layout tag.
@@ -73,6 +78,11 @@ public virtual async Task RenderPartialAsync(TextWriter writer, string relativeP
// Substitute View Path
context.AmbientValues[Constants.ViewPathIndex] = relativePath;
+ if (_fluidViewEngineOptions.RenderingViewAsync != null)
+ {
+ await _fluidViewEngineOptions.RenderingViewAsync.Invoke(relativePath, context);
+ }
+
var template = await GetFluidTemplateAsync(relativePath, _fluidViewEngineOptions.PartialsFileProvider, false);
await template.RenderAsync(writer, _fluidViewEngineOptions.TextEncoder, context);