c# - 将 Blazor RenderFragment 参数转发给子组件会引发异常

标签 c# .net-core blazor

更新:Microsoft 已确认此问题。 ( Github issue ),并且可能会在 .Net 6 ( github issue ) 中修复/解决。


我可以使用 RenderFragment 将(子)内容传递给组件。这可以是可选的。取:

@*Baz.razor*@
@if (Bar is null)
{
    <div>nobar</div>
}
else
{
    <div>Render bar: @Bar</div>
}

@code {
    [Parameter]
    public RenderFragment Bar { get; set; }
}

我能做到

@*FooPage.razor*@
@page "/foopage"
<Baz />

呈现“nobar”,或

@*FooPage.razor*@
@page "/foopage"
<Baz Bar=@bar/>

@code {
    private RenderFragment bar = (builder) => { builder.AddMarkupContent(0, "<div>bar</div>"); };
}

渲染“Render bar: bar”(由于 div 而带有换行符)

所以,现在我遇到了一个新情况,两者之间有一个名为 Foo 的组件。

@*Foo.razor*@
<Baz Bar=@Bar />

@code {
    [Parameter]
    public RenderFragment Bar { get; set; }
}

我将 FooPage.razor 修改为

@*FooPage.razor*@
@page "/foopage"
<Foo />

即我将 Bar 参数从 Foo 转发到 Baz...这不起作用,并给了我一个相当长的错误(在这个问题的底部)。 (注意:当我在 FooPage 中分配 Bar 时,它确实有效。)

这对我来说很奇怪。我可以检查 Bar 是否为空,并使用它。但是,我无法显式将 Bar 设置为 null,或传递 null 引用。

我也直接尝试过这样做:

@*FooPage.razor*@
@page "/foopage"
<Foo Bar=@nullrf />

@code {
    private RenderFragment nullrf;
}

它也会抛出相同的异常。

即如果你把它省略,它就是空的,但是如果你把它指定为空,它就会中断。这是一个错误吗?

ArgumentException: Delegate to an instance method cannot have null 'this'.
System.MulticastDelegate.ThrowNullThisInDelegateToInstance()
System.MulticastDelegate.CtorClosed(object target, IntPtr methodPtr)
BlazorServerDefault.Pages.Foo.BuildRenderTree(RenderTreeBuilder __builder)
Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder)
Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessPendingRender()
Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(int componentId, RenderFragment renderFragment)
Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToPendingTasks(Task task)
Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(int componentId, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.CreateInitialRenderAsync(Type componentType, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.RenderComponentAsync(Type componentType, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext+<>c__11<TResult>+<<InvokeAsync>b__11_0>d.MoveNext()
Microsoft.AspNetCore.Mvc.ViewFeatures.StaticComponentRenderer.PrerenderComponentAsync(ParameterView parameters, HttpContext httpContext, Type componentType)
Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.PrerenderedServerComponentAsync(HttpContext context, ServerComponentInvocationSequence invocationId, Type type, ParameterView parametersCollection)
Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.RenderComponentAsync(ViewContext viewContext, Type componentType, RenderMode renderMode, object parameters)
Microsoft.AspNetCore.Mvc.TagHelpers.ComponentTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, int i, int count)
BlazorServerDefault.Pages.Pages__Host.<ExecuteAsync>b__14_1() in _Host.cshtml
+
    <component type="typeof(App)" render-mode="ServerPrerendered" />
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
BlazorServerDefault.Pages.Pages__Host.ExecuteAsync() in _Host.cshtml
+
    Layout = null;
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

最佳答案

当您尝试将 Bar 作为属性传递时,Razor 编译器将尝试将其呈现为 Foo 组件的一部分,这不是您想要的,也是当 Bar 为属性时失败的原因空。

您可以通过属性展开来实现您的目标 - 如果实际用例适合这一点。

@*Foo.razor*@
<Baz @attributes=PassThrough/>

@code {
    [Parameter]
    public RenderFragment Bar { get; set; }
    Dictionary<string,object> PassThrough;
    protected override void OnInitialized()
    {
        PassThrough = new Dictionary<string,object>();
        PassThrough.Add(nameof(Baz.Bar),this.Bar);
    }
}

编辑:在这里测试:Blazor Repl

关于c# - 将 Blazor RenderFragment 参数转发给子组件会引发异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66396746/

相关文章:

.net-core - 在 nexus 上使用 nuget 代理时,dotnet 还原失败

unit-testing - dotnet 核心的无约束隔离(模拟)框架

docker - 无法使用 Nginx 在 Blazor docker compose 配置中转发真实客户端 IP 地址

c# - 如何限制.net core api中每分钟的请求数

c# - 如何使用 Visual Studio 2019 清理/检查 blazor 组件中的代码

Blazor 渲染片段子内容只允许某些组件?

c# - 对象或值作为我的服务/数据层的参数

c# - 枚举标志负值

C# - 使用子类实现接口(interface)

c# - 如何确定远程处理 channel 是否已注册