admin管理员组文章数量:1122832
I am using ASP.NET Core to build a simple login with multiple Blazor components.
I want to store my AppState
such as IsLoggedIn
inside my AppState
code and subscribe to the OnChange
method for UI updates.
namespace PulseVenture.PhotoGallery.Components.Services.State
{
public class AppState
{
public Guid InstanceId { get; } = Guid.NewGuid();
public AppState()
{
Console.WriteLine($"AppState instance created at {DateTime.Now} with ID: {InstanceId}");
}
public bool IsLoggedIn { get; private set; }
public string? UserName { get; private set; }
public event Action? OnChange;
// LogIn Methode needs Validation @ToDo
public void LogIn(string? userName)
{
IsLoggedIn = true;
UserName = userName;
NotifyStateChanged();
}
public void LogOut()
{
IsLoggedIn = false;
UserName = null;
NotifyStateChanged();
}
// Invoke, updating the UI or performing other actions
//private void NotifyStateChanged() => OnChange?.Invoke();
private void NotifyStateChanged()
{
Console.WriteLine($"NotifyStateChanged invoked. OnChange is {(OnChange == null ? "null" : "not null")}. with Instance: {InstanceId}");
if (OnChange == null)
{
Console.WriteLine($"Warning: OnChange is null when NotifyStateChanged is called. with Instance: {InstanceId}");
}
OnChange?.Invoke();
}
}
}
Inside my components such as the NavMenu I am injecting the AppState
.
@using Components.Services.State
@implements IDisposable
@inject AppState AppState
...
@if (AppState.IsLoggedIn)
{
<Layout.NavComponents.UploadButton />
}
else
{
<Layout.NavComponents.LogInButton />
}
...
@code {
//SingOut Logic
private void LogOut() => AppState.LogOut();
// subscribe to the OnChange event and trigger a re-render with StateHasChanged
protected override void OnInitialized()
{
Console.WriteLine($"Component initialized with AppState instance: {AppState.InstanceId}");
if (AppState != null)
{
AppState.OnChange += () =>
{
Console.WriteLine($"State changed detected in component. with Instance: {AppState.InstanceId}");
StateHasChanged();
};
Console.WriteLine($"Subscribed to AppState.OnChange with Instance: {AppState.InstanceId}");
}
else
{
Console.WriteLine("AppState is null in OnInitialized");
}
}
public void Dispose()
{
if (AppState != null)
{
Console.WriteLine($"Disposed instance: {AppState.InstanceId}");
AppState.OnChange -= StateHasChanged;
}
}
}
And inside my LogInButton
is a child component named LogInPopUp
which also uses the AppState
:
@rendermode InteractiveServer
@using Components.Services.State
@implements IDisposable
@inject AppState AppState
<div class="popup-backdrop" style="@(Show ? "display:block;" : "display:none;")">
<div class="card popup-content">
<button class="exit-btn" @onclick="ClosePopup">
<svg xmlns="; height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z" />
</svg>
</button>
<span class="card_title">Log In</span>
<p class="card_content">Upload Documents to share straight to your cliends.
</p>
<div class="card_form">
<input placeholder="Your Email" type="text" @bind="UserEmail">
<button class="sign-in" @onclick="LogIn"> Sign In</button>
</div>
<p class="signup-link">
No Account?
<a href="">Request Access</a>
</p>
</div>
</div>
@code {
[Parameter]
public bool Show { get; set; }
[Parameter]
public EventCallback<bool> ShowChanged { get; set; }
private async Task ClosePopup()
{
Show = false;
if (ShowChanged.HasDelegate)
{
await ShowChanged.InvokeAsync(Show);
}
}
// LogIn Logic
private string UserEmail = string.Empty;
private void LogIn()
{
AppState.LogIn(UserEmail);
ClosePopup();
}
protected override void OnInitialized()
{
Console.WriteLine($"Component initialized with AppState instance: {AppState.InstanceId}");
if (AppState != null)
{
AppState.OnChange += () =>
{
Console.WriteLine($"State changed detected in component. with Instance: {AppState.InstanceId}");
StateHasChanged();
};
Console.WriteLine($"Subscribed to AppState.OnChange with Instance: {AppState.InstanceId}");
}
else
{
Console.WriteLine("AppState is null in OnInitialized");
}
}
public void Dispose()
{
if (AppState != null)
{
Console.WriteLine($"Disposed instance: {AppState.InstanceId}");
AppState.OnChange -= StateHasChanged;
}
}
}
But when I run my code, I get the output that both elements subscribe to the appState
and when they are done rendering they immediately dispose of the AppState
and create a new instance.
Output:
AppState instance created at 21.11.2024 18:17:02 with ID: 872221af-23da-4427-8dc5-c5b5ac0e9f45
Component initialized with AppState instance: 872221af-23da-4427-8dc5-c5b5ac0e9f45
Subscribed to AppState.OnChange with Instance: 872221af-23da-4427-8dc5-c5b5ac0e9f45
Component initialized with AppState instance: 872221af-23da-4427-8dc5-c5b5ac0e9f45
Subscribed to AppState.OnChange with Instance: 872221af-23da-4427-8dc5-c5b5ac0e9f45
Disposed instance: 872221af-23da-4427-8dc5-c5b5ac0e9f45
Disposed instance: 872221af-23da-4427-8dc5-c5b5ac0e9f45
I inject the AppState
as a scoped DI.
I already tried using different DI injections but I technically need to use
builder.Services.AddScoped<AppState>();
because my application can have more than one user.
Furthermore I tried passing the AppState
down from the parent which also doesn't work.
本文标签: cASPNET Core Blazor gt Scoped AppState lifecycle of Blazor componentsStack Overflow
版权声明:本文标题:c# - ASP.NET Core Blazor -> Scoped AppState lifecycle of Blazor components - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736307792a1933434.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论