Skip to content

Root-level cascading value is Singleton instead of Scoped #63844

@vsfeedback

Description

@vsfeedback

This issue has been moved from a ticket on Developer Community.


[severity:It's more difficult to complete my work]
I have followed the steps here to create a Root-level cascading value with notifications (Blazor Server)
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/cascading-values-and-parameters?view=aspnetcore-9.0#root-level-cascading-values-with-notifications

It works great, except for one thing: The instance is a singleton. So in two different browsers, the Cascading Value is the same. Thus when a user changes a value (for example the current Theme), it changes the Theme of all connected users.

What is needed is a Scoped Root Level Cascading Value.

This is the code that adds the Service. As you can see, it is created in Program.cs and thus is going to be a singleton.

builder. Services.AddNotifyingCascadingValue(new NotifyingDalek() { Units = 888 });

I have tried, but I have not found a way to Add NotifyingDalek as a Scoped Service, and then add it using

builder. Services.AddNotifyingCascadingValue<NotifyingDalek>();

Any advice would be appreciated.


Original Comments

Feedback Bot on 9/26/2025, 03:09 AM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.


Original Solutions

Greg Gum solved on 9/25/2025, 06:07 PM, undefined votes:

I was able to update the Registration Code as follows, and then call it as usual:

builder. Services.AddNotifyingCascadingValue<ThemeService>();
public static class CascadingStateServiceCollectionExtensions
{
    public static IServiceCollection AddNotifyingCascadingValue<TState, TImplementation>(
        this IServiceCollection services, bool isFixed = false)
        where TState : class, INotifyPropertyChanged
        where TImplementation : class, TState
    {
        // Register the implementation as Scoped
        services. AddScoped<TImplementation>();

return services. AddCascadingValue<TState>(sp =>
{
var state = sp. GetRequiredService<TImplementation>();
return new CascadingStateValueSource<TState>(state, isFixed);
});
}

// Overload for cases where TState and TImplementation are the same
public static IServiceCollection AddNotifyingCascadingValue<TState>(
this IServiceCollection services, bool isFixed = false)
where TState : class, INotifyPropertyChanged
{
return AddNotifyingCascadingValue<TState, TState>(services, isFixed);
}

private sealed class CascadingStateValueSource<T>
: CascadingValueSource<T>, IDisposable where T : INotifyPropertyChanged
{
private readonly T state;

public CascadingStateValueSource(T state, bool isFixed = false)
: base(state, isFixed)
{
this.state = state;
this.state.PropertyChanged += HandlePropertyChanged;
}

private void HandlePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
_ = NotifyChangedAsync();
}

public void Dispose()
{
state. PropertyChanged -= HandlePropertyChanged;
}
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    ✔️ Resolution: AnsweredResolved because the question asked by the original author has been answered.Author: Migration Bot 🤖The issue was created by a issue mover bot. The author may not be the actual author.Status: Resolvedarea-blazorIncludes: Blazor, Razor Componentsquestion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions