Description
Blazor persistent service serialization does not use the JSON metadata resolvers configured through CircuitOptions.JsonTypeInfoResolvers. As a result, pausing an interactive server circuit throws when System.Text.Json reflection-based serialization is disabled, including in Native AOT applications.
This was observed with .NET 11.0.0-rc.1.26425.128.
Reproduction
Configure an interactive server application with reflection serialization disabled and a generated context:
<PropertyGroup>
<PublishAot>true</PublishAot>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
services.AddRazorComponents().AddInteractiveServerComponents(options =>
{
#pragma warning disable ASPNETCORE9004
options.JsonTypeInfoResolvers.Add(AppJsonSerializerContext.Default);
#pragma warning restore ASPNETCORE9004
});
Start an interactive server circuit and pause it. The persistent service callback fails:
System.InvalidOperationException: Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled()
at System.Text.Json.JsonSerializerOptions.ConfigureForJsonSerializer()
at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
at System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(Object value, Type inputType, JsonSerializerOptions options)
at Microsoft.AspNetCore.Components.PersistentComponentState.PersistAsJson(String key, Object instance, Type type)
at Microsoft.AspNetCore.Components.Infrastructure.PersistentServicesRegistry.PersistInstanceState(Object instance, Type type, PersistentComponentState state)
at Microsoft.AspNetCore.Components.Infrastructure.PersistentServicesRegistry.<>c__DisplayClass14_1.<RegisterForPersistence>b__1()
at Microsoft.AspNetCore.Components.Infrastructure.ComponentStatePersistenceManager.<TryPauseAsync>g__TryExecuteCallback|21_0(Func`1 callback, ILogger`1 logger)
Cause
PersistentServicesRegistry.PersistInstanceState calls the non-generic PersistentComponentState.PersistAsJson(key, value, propertyType) overload:
https://github.com/dotnet/dotnet/blob/3551975be08744f0418857c5bed8ab1545c5dd47/src/aspnetcore/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs#L119-L129
That overload always uses the internal JsonSerializerOptionsProvider.Options:
https://github.com/dotnet/dotnet/blob/3551975be08744f0418857c5bed8ab1545c5dd47/src/aspnetcore/src/Components/Components/src/PersistentComponentState.cs#L127-L138
It therefore cannot see the source-generated contexts in CircuitOptions.JsonTypeInfoResolvers.
For the persistent services registered by AddRazorComponents, the generated serialization context needs metadata for these [PersistentState] property types:
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(Microsoft.AspNetCore.Components.Forms.AntiforgeryRequestToken))]
internal partial class AppJsonSerializerContext : JsonSerializerContext;
Specifically:
ResourceCollectionProvider.ResourceCollectionUrl requires System.String.
DefaultAntiforgeryStateProvider.CurrentToken requires Microsoft.AspNetCore.Components.Forms.AntiforgeryRequestToken.
- Application-registered persistent services additionally require metadata for each property type marked with
[PersistentState].
Adding these types to the application context does not help today because the persistent service path does not consume that context.
Expected behavior
Persistent service persistence and restoration should use the configured CircuitOptions.JsonTypeInfoResolvers, or expose an equivalent supported options/serializer hook, so Native AOT applications can provide generated metadata for all persistent property types.
Workaround limitations
Setting JsonSerializerIsReflectionEnabledByDefault=true avoids the runtime exception, but it is not a viable Native AOT workaround. It roots DefaultJsonTypeInfoResolver through Microsoft.AspNetCore.Http.Json.JsonOptions.CreateDefaultTypeResolver and produces IL2026/IL3050 trim and AOT analysis errors. Removing the framework persistent service registrations also loses resource collection and antiforgery state across persistence.
Description
Blazor persistent service serialization does not use the JSON metadata resolvers configured through
CircuitOptions.JsonTypeInfoResolvers. As a result, pausing an interactive server circuit throws whenSystem.Text.Jsonreflection-based serialization is disabled, including in Native AOT applications.This was observed with .NET
11.0.0-rc.1.26425.128.Reproduction
Configure an interactive server application with reflection serialization disabled and a generated context:
Start an interactive server circuit and pause it. The persistent service callback fails:
Cause
PersistentServicesRegistry.PersistInstanceStatecalls the non-genericPersistentComponentState.PersistAsJson(key, value, propertyType)overload:https://github.com/dotnet/dotnet/blob/3551975be08744f0418857c5bed8ab1545c5dd47/src/aspnetcore/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs#L119-L129
That overload always uses the internal
JsonSerializerOptionsProvider.Options:https://github.com/dotnet/dotnet/blob/3551975be08744f0418857c5bed8ab1545c5dd47/src/aspnetcore/src/Components/Components/src/PersistentComponentState.cs#L127-L138
It therefore cannot see the source-generated contexts in
CircuitOptions.JsonTypeInfoResolvers.For the persistent services registered by
AddRazorComponents, the generated serialization context needs metadata for these[PersistentState]property types:Specifically:
ResourceCollectionProvider.ResourceCollectionUrlrequiresSystem.String.DefaultAntiforgeryStateProvider.CurrentTokenrequiresMicrosoft.AspNetCore.Components.Forms.AntiforgeryRequestToken.[PersistentState].Adding these types to the application context does not help today because the persistent service path does not consume that context.
Expected behavior
Persistent service persistence and restoration should use the configured
CircuitOptions.JsonTypeInfoResolvers, or expose an equivalent supported options/serializer hook, so Native AOT applications can provide generated metadata for all persistent property types.Workaround limitations
Setting
JsonSerializerIsReflectionEnabledByDefault=trueavoids the runtime exception, but it is not a viable Native AOT workaround. It rootsDefaultJsonTypeInfoResolverthroughMicrosoft.AspNetCore.Http.Json.JsonOptions.CreateDefaultTypeResolverand producesIL2026/IL3050trim and AOT analysis errors. Removing the framework persistent service registrations also loses resource collection and antiforgery state across persistence.