Skip to content

Commit

Permalink
Add rendering event (#464)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienros authored Apr 1, 2022
1 parent f2f99f9 commit f61b88f
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 23 deletions.
22 changes: 8 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 8 additions & 1 deletion Fluid.MvcViewEngine/FluidMvcViewOptions.cs
Original file line number Diff line number Diff line change
@@ -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);

/// <summary>
/// Gets or sets the delegate to execute when a view is rendered.
/// </summary>
public new RenderingMvcViewDelegate RenderingViewAsync { get; set; }
}
}
16 changes: 11 additions & 5 deletions Fluid.MvcViewEngine/FluidRendering.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 7 additions & 1 deletion Fluid.MvcViewEngine/FluidTagHelper.cs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,6 +16,10 @@ public FluidTagHelper(FluidRendering fluidRendering)
_fluidRendering = fluidRendering;
}

[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }

[HtmlAttributeName("model")]
public object Model { get; set; }

Expand All @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion Fluid.MvcViewEngine/FluidView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
17 changes: 16 additions & 1 deletion Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
12 changes: 12 additions & 0 deletions Fluid.ViewEngine/FluidViewEngineOptions.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand Down Expand Up @@ -62,5 +64,15 @@ public class FluidViewEngineOptions
/// Gets or sets whether files should be reloaded automatically when changed. Default is <code>true</code>;
/// </summary>
public bool TrackFileChanges { get; set; } = true;

/// <summary>
/// <para>Represents the method that will handle the view rendering event.</para>
/// </summary>
public delegate ValueTask RenderingViewDelegate(string path, TemplateContext context);

/// <summary>
/// Gets or sets the delegate to execute when a view is rendered.
/// </summary>
public RenderingViewDelegate RenderingViewAsync { get; set; }
}
}
10 changes: 10 additions & 0 deletions Fluid.ViewEngine/FluidViewRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit f61b88f

Please sign in to comment.