Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions BlazorTemplater.Library/AsyncRender.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<h3>AsyncRender Text: @Text</h3>

@code {
public string Text { get; set; } = "Original value";

protected override async Task OnInitializedAsync()
{
await Task.Delay(500);
Text = "Async value";
await base.OnInitializedAsync();
}
}
21 changes: 20 additions & 1 deletion BlazorTemplater.Tests/ComponentRenderer_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading.Tasks;

namespace BlazorTemplater.Tests
{
Expand Down Expand Up @@ -100,7 +101,7 @@ public void ComponentBuilder_Parameters_TestIfModelNotSet()
// expected output
const string expected = "<p>No model!</p>";

var html = new ComponentRenderer<Parameters>()
var html = new ComponentRenderer<Parameters>()
.Render();

// trim leading space and trailing CRLF from output
Expand All @@ -112,6 +113,24 @@ public void ComponentBuilder_Parameters_TestIfModelNotSet()

#endregion Parameters

#region Async render

/// <summary>
/// Test a async render, so the html is generated only after the async lifecycle is completed
/// </summary>
[TestMethod]
public async Task Async_Test()
{
const string expected = @"<h3>AsyncRender Text: Async value</h3>";

var actual = await new ComponentRenderer<AsyncRender>().RenderAsync();

Console.WriteLine(actual);
Assert.AreEqual(expected, actual);
}

#endregion Async render

#region Errors

/// <summary>
Expand Down
21 changes: 21 additions & 0 deletions BlazorTemplater.Tests/Templater_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace BlazorTemplater.Tests
{
Expand Down Expand Up @@ -137,6 +138,26 @@ public void RenderComponent_Parameters_TestIfModelNotSet()

#endregion Parameters


#region Async render

/// <summary>
/// Test a async render, so the html is generated only after the async lifecycle is completed
/// </summary>
[TestMethod]
public async Task RenderComponent_Async_Test()
{
const string expected = @"<h3>AsyncRender Text: Async value</h3>";

var templater = new Templater();
var actual = await templater.RenderComponentAsync<AsyncRender>();

Console.WriteLine(actual);
Assert.AreEqual(expected, actual);
}

#endregion Async render

#region Errors

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions BlazorTemplater.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31624.102
# Visual Studio Version 17
VisualStudioVersion = 17.3.32811.315
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{C0365D75-5C0A-4E88-BC0F-FF595B731B6B}"
ProjectSection(SolutionItems) = preProject
Expand Down
4 changes: 2 additions & 2 deletions BlazorTemplater/BlazorTemplater.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<PackageProjectUrl>https://github.com/conficient/BlazorTemplater</PackageProjectUrl>
<RepositoryUrl>https://github.com/conficient/BlazorTemplater</RepositoryUrl>
<PackageTags>Blazor RazorComponents HTML Email Templating</PackageTags>
<Version>1.5.0</Version>
<PackageReleaseNotes>Added ability to inject an entire IServiceProvider</PackageReleaseNotes>
<Version>1.6.0</Version>
<PackageReleaseNotes>Added ability to await the completion of the async lifecycle before generating the output html so to include all possible updates from the async methods</PackageReleaseNotes>
<LangVersion>Latest</LangVersion>
</PropertyGroup>

Expand Down
11 changes: 11 additions & 0 deletions BlazorTemplater/ComponentRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;

namespace BlazorTemplater
{
Expand Down Expand Up @@ -154,5 +155,15 @@ public string Render()
// renders the component and returns the markup HTML
return templater.RenderComponent<TComponent>(parameters);
}

/// <summary>
/// Render the component to HTML waiting all the async lifecycle to complete
/// </summary>
/// <returns></returns>
public Task<string> RenderAsync()
{
// renders the component and returns the markup HTML
return templater.RenderComponentAsync<TComponent>(parameters);
}
}
}
8 changes: 8 additions & 0 deletions BlazorTemplater/ContainerComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ public void RenderComponentUnderTest(Type componentType, ParameterView parameter
builder.CloseComponent();
});
});

}

public Task RenderComponentUnderTestAsync(Type componentType, ParameterView parameters)
{
RenderComponentUnderTest(componentType, parameters);
return _renderer.AwaitAllPendingTasks();

}
}
}
5 changes: 5 additions & 0 deletions BlazorTemplater/HtmlRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,10 @@ private void AssertNoSynchronousErrors()
ExceptionDispatchInfo.Capture(_unhandledException).Throw();
}
}

internal Task AwaitAllPendingTasks()
{
return NextRender;
}
}
}
10 changes: 10 additions & 0 deletions BlazorTemplater/RenderedComponent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components;
using System.Threading.Tasks;

namespace BlazorTemplater
{
Expand Down Expand Up @@ -37,5 +38,14 @@ internal void SetParametersAndRender(ParameterView parameters)
_testComponentId = foundTestComponent.Item1;
_testComponentInstance = (TComponent)foundTestComponent.Item2;
}

internal async Task SetParametersAndRenderAsync(ParameterView parameters)
{
await _containerTestRootComponent.RenderComponentUnderTestAsync(
typeof(TComponent), parameters);
var foundTestComponent = _containerTestRootComponent.FindComponentUnderTest();
_testComponentId = foundTestComponent.Item1;
_testComponentInstance = (TComponent)foundTestComponent.Item2;
}
}
}
53 changes: 53 additions & 0 deletions BlazorTemplater/Templater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlazorTemplater
{
Expand Down Expand Up @@ -114,6 +115,21 @@ public string RenderComponent<TComponent>(IDictionary<string, object> parameters
return RenderComponent(componentType, parameters);
}

/// <summary>
/// Render a component to HTML waiting all the async lifecycle to complete
/// </summary>
/// <typeparam name="TComponent">The component type to render</typeparam>
/// <param name="parameters">Optional dictionary of parameters</param>
/// <returns></returns>
/// <remarks>
/// Updated version renders inside a LayoutView so that layouts are applied
/// </remarks>
public Task<string> RenderComponentAsync<TComponent>(IDictionary<string, object> parameters = null) where TComponent : IComponent
{
var componentType = typeof(TComponent);
return RenderComponentAsync(componentType, parameters);
}

/// <summary>
/// Render a component to HTML (non-generic version)
/// </summary>
Expand Down Expand Up @@ -151,6 +167,43 @@ public string RenderComponent(Type componentType, IDictionary<string, object> pa
return layoutView.GetMarkup();
}

/// <summary>
/// Render a component to HTML (non-generic version) it waits untill all the async life cycles are completed
/// </summary>
/// <param name="componentType">the Type of the component</param>
/// <param name="parameters">Optional dictionary of parameters</param>
/// <returns></returns>
/// <remarks>
/// This non-generic version can accept a Type
/// </remarks>
public async Task<string> RenderComponentAsync(Type componentType, IDictionary<string, object> parameters = null)
{
ValidateComponentType(componentType);
var layout = GetLayout(componentType);

// create a RenderFragment from the component
var childContent = (RenderFragment)(builder =>
{
builder.OpenComponent(0, componentType);

// add parameters if any
if (parameters != null && parameters.Any())
builder.AddMultipleAttributes(1, parameters);
builder.CloseComponent();
});

// render a LayoutView and use the TComponent as the child content
var layoutView = new RenderedComponent<LayoutView>(Renderer);
var layoutParams = new Dictionary<string, object>()
{
{ nameof(LayoutView.Layout), layout },
{ nameof(LayoutView.ChildContent), childContent }
};
await layoutView.SetParametersAndRenderAsync(GetParameterView(layoutParams));

return layoutView.GetMarkup();
}

/// <summary>
/// Check that a Type is an IComponent
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,6 @@ This was never developed into a functioning product or library. For unit testing
| v1.2.0 | Added multi-targetting for .NET Std/.NET 5 to fix bug [#12](https://github.com/conficient/BlazorTemplater/issues/12) |
| v1.3.0 | Added `ComponentRenderer<T>` for fluent interface and typed parameter setting |
| v1.4.0 | Added support for Layouts |
| v1.5.0 | Added support already existing IServiceProvider |
| v1.6.0 | Added support AsyncRender |