dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.43k stars 10.01k forks source link

DynamicComponent Throws Run-Time Error on .NET 8 #51901

Open sbwalker opened 12 months ago

sbwalker commented 12 months ago

Is there an existing issue for this?

Describe the bug

When using the standard DynamicComponent (introduced in .NET 6) and specifying an instance-based @rendermode attribute ie.

<DynamicComponent Type="@_type" @rendermode="RenderMode.InteractiveServer">

The component throws a run-time error related to serialization:

An unhandled exception occurred while processing the request.
NotSupportedException: Serialization and deserialization of 'System.RuntimeType' instances is not supported.
System.Text.Json.Serialization.Converters.UnsupportedTypeConverter<T>.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
I tried including only one DynamicComponent at a time and they still threw an exception. So specifying the rendermode on the instance does NOT work for dynamic components.

DynamicComponent expects a Type parameter which is of type System.RuntimeType - however in .NET 8 parameters must be serializable.

Expected Behavior

DynamicComponent is widely used in Blazor applications to construct razor components dynamically based on type information. I would expect DynamicComponent to render a component in exactly the same manner as it does in .NET 6 and .NET 7.

Steps To Reproduce

Please see repo: https://github.com/oqtane/OqtaneSSR which is based on the standard Blazor Web template in .NET 8 RC2. Set the appsettings.json Modules property to:

 "Modules": [
   {
     "PagePath": "/",
     "PageName": "Home",
     "ThemeType": "OqtaneSSR.Components.Themes.MainLayout, OqtaneSSR",
     "PaneName": "Default",
     "ContainerType": "OqtaneSSR.Components.Containers.Container2, OqtaneSSR",
     "ModuleType": "OqtaneSSR.Client.Components.Home, OqtaneSSR.Client",
     "RenderMode": "InteractiveServer"
   },
   {
     "PagePath": "/counter",
     "PageName": "Counter",
     "ThemeType": "OqtaneSSR.Components.Themes.MainLayout, OqtaneSSR",
     "PaneName": "Default",
     "ContainerType": "OqtaneSSR.Components.Containers.Container2, OqtaneSSR",
     "ModuleType": "OqtaneSSR.Client.Components.Counter, OqtaneSSR.Client",
     "RenderMode": "InteractiveServer"
   },
   {
     "PagePath": "/weather",
     "PageName": "Weather",
     "ThemeType": "OqtaneSSR.Components.Themes.MainLayout, OqtaneSSR",
     "PaneName": "Default",
     "ContainerType": "OqtaneSSR.Components.Containers.Container2, OqtaneSSR",
     "ModuleType": "OqtaneSSR.Client.Components.Weather, OqtaneSSR.Client",
     "RenderMode": "InteractiveServer"
   }
 ]

When you run the application, it will immediately throw a run-time error. This is caused by the line:

<DynamicComponent Type="@_type" @rendermode="RenderMode.InteractiveServer">

in OqtaneSSR\Components\Router\ModuleInstance2.razor

Exceptions (if any)

An unhandled exception occurred while processing the request. NotSupportedException: Serialization and deserialization of 'System.RuntimeType' instances is not supported. System.Text.Json.Serialization.Converters.UnsupportedTypeConverter.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)

.NET Version

8.0.0-rc.2.23480.2

Anything else?

A workaround to this problem is to create a custom component which accepts a TypeName (rather than a Type) and use RenderFragment to render it:

@DynamicComponent

@code {
    [Parameter]
    public string TypeName { get; set; }

    RenderFragment DynamicComponent { get; set; }

    protected override void OnParametersSet()
    {
        DynamicComponent = builder =>
        {
            builder.OpenComponent(0, Type.GetType(TypeName));
            builder.CloseComponent();
        };
    }
}

Note that this workaround does not support Parameters - which is another problem with DynamicComponent as it uses a Dictionary for parameters.

ghost commented 10 months ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost commented 9 months ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.