conficient / BlazorTemplater

A library that generates HTML (e.g. for emails) from Razor Components

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No support for cascading parameter

aravind-imonitor opened this issue · comments

So it seems there is support for cascading value but not cascading parameters.

I modified the method GetParameterName in ComponentRenderer to also get CascadingAttribute

private static string GetParameterName<TValue>(Expression<Func<TComponent, TValue>> parameterSelector)
{
    if (parameterSelector is null)
        throw new ArgumentNullException(nameof(parameterSelector));

    if (parameterSelector.Body is not MemberExpression memberExpression ||
        memberExpression.Member is not PropertyInfo propInfoCandidate)
        throw new ArgumentException($"The parameter selector '{parameterSelector}' does not resolve to a public property on the component '{typeof(TComponent)}'.", nameof(parameterSelector));

    var propertyInfo = propInfoCandidate.DeclaringType != TComponentType
        ? TComponentType.GetProperty(propInfoCandidate.Name, propInfoCandidate.PropertyType)
        : propInfoCandidate;

   //Changed ParameterAttribute to Attribute, as CascadingParameter inherits from Attribute not ParameterAttribute
    var paramAttr = propertyInfo?.GetCustomAttribute<Attribute>(inherit: true);

    if (propertyInfo is null || paramAttr is null)
        throw new ArgumentException($"The parameter selector '{parameterSelector}' does not resolve to a public property on the component '{typeof(TComponent)}' with a [Parameter] or [CascadingParameter] attribute.", nameof(parameterSelector));

    return propertyInfo.Name;
}

I also added a test case for the CascadeChild which contains a cascading parameter in ComponentRenderer_Tests, but it throws exception

[TestMethod]
public void ComponentRenderer_CascadingValues_Test_2()
{
    const string expected = "<p>The name is Bill</p>";
    var info = new CascadeInfo() { Name = "Bill" };

    var html = new ComponentRenderer<CascadeChild>()
        .Set(c => c.Info, info)
        .Render();

    // trim leading space and trailing CRLF from output
    var actual = html.Trim();

    Assert.AreEqual(expected, actual);

}

Exception
System.InvalidOperationException HResult=0x80131509 Message=Object of type 'BlazorTemplater.Library.CascadeChild' has a property matching the name 'Info', but it does not have [ParameterAttribute] applied. Source=Microsoft.AspNetCore.Components StackTrace: at Microsoft.AspNetCore.Components.Reflection.ComponentProperties.ThrowForSettingCascadingParameterWithNonCascadingValue(Type targetType, String parameterName) at Microsoft.AspNetCore.Components.Reflection.ComponentProperties.SetProperties(ParameterView& parameters, Object target) at Microsoft.AspNetCore.Components.ParameterView.SetParameterProperties(Object target) at Microsoft.AspNetCore.Components.ComponentBase.SetParametersAsync(ParameterView parameters) at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange1 oldTree, ArrayRange1 newTree) at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment) at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry) at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue() --- End of stack trace from previous location --- at BlazorTemplater.HtmlRenderer.AssertNoSynchronousErrors() in C:\VSTS\BlazorTemplater\BlazorTemplater\HtmlRenderer.cs:line 71 at BlazorTemplater.HtmlRenderer.DispatchAndAssertNoSynchronousErrors(Action callback) in C:\VSTS\BlazorTemplater\BlazorTemplater\HtmlRenderer.cs:line 64 at BlazorTemplater.ContainerComponent.RenderComponentUnderTest(Type componentType, ParameterView parameters) in C:\VSTS\BlazorTemplater\BlazorTemplater\ContainerComponent.cs:line 61 at BlazorTemplater.RenderedComponent1.SetParametersAndRender(ParameterView parameters) in C:\VSTS\BlazorTemplater\BlazorTemplater\RenderedComponent.cs:line 34 at BlazorTemplater.Templater.RenderComponent(Type componentType, IDictionary2 parameters) in C:\VSTS\BlazorTemplater\BlazorTemplater\Templater.cs:line 149 at BlazorTemplater.Templater.RenderComponent[TComponent](IDictionary2 parameters) in C:\VSTS\BlazorTemplater\BlazorTemplater\Templater.cs:line 114 at BlazorTemplater.ComponentRenderer1.Render() in C:\VSTS\BlazorTemplater\BlazorTemplater\ComponentRenderer.cs:line 188 at BlazorTemplater.Tests.ComponentRenderer_Tests.ComponentRenderer_CascadingValues_Test_2() in C:\VSTS\BlazorTemplater\BlazorTemplater.Tests\ComponentRenderer_Tests.cs:line 239

My bad, just had a deeper look, I was using it wrong.
Only set back is I have lot of components that depend on cascading parameters, and I just want the html of these child components, so need to find a way to be able to set cascading parameter. The example with CascadingParent is working from top down, meaning the parameter value is being set at the parent level and this value is then being passed to CascadeChild. Is there anyway to only get the html of the CascadeChild component like the test case I wrote?