我有一个 Blazor 服务器应用程序,其中注册了一个服务来维护状态,如下所示:
public class AppState
{
public bool IsAuthenticated { get; set; }
public string UserId { get; set; }
}
在
program.cs
builder.Services.AddScoped<AppState>();
在
Index.razor
中 OnInitialized()
我在 AppState 中设置了一些值:
@inject AppState AppState
protected override void OnInitialized()
{
AppState.UserId = "logged in userid";
}
我将此服务注入到组件中,以获取范围服务所需的任何内容。
但是,如果我在 DataService.cs(也在范围内)中执行此操作并创建 ApplicationDbContext 的实例:
public class DataService
{
private IServiceScopeFactory _scopeFactory;
private AppState _appState;
public DataService(IServicesScopeFactory scopeFactory, AppState appState)
{
_scopeFactory = scopeFactory;
_appState = appState;
}
public async Task<List<Patient>> GetAllPatientsAsync()
{
List<Patient> patients = new List<Patient>();
using (var scope = _scopeFactory.CreateScope())
{
var context =
scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
//access the ApplicationDbContext
}
return patients;
}
public class ApplicationDbContext : IdentityDbContext
{
public Guid _tenantId;
AppState _state;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext>
options, ITenantProvider _tenantProvider, AppState appState)
: base(options)
{
_tenantId = _tenantProvider.GetTenantId();
_state = appState; //seems a new instance of AppState is provided
here...
}
似乎 AppState 已重新初始化(在新创建的 ApplicationDbContext 内),并且我没有获得在 Index.razor 中设置的 userId 的值。在我看来,当我使用 ScopeFactory 创建一个范围并从该范围调用 ApplicationDbContext 时,就会创建一个新的 AppState 范围实例。
这个问题有什么解决办法吗?我需要保留原来的 AppState。
您可以使用会话存储来维护状态。这里只是示例代码供您参考:
AppState.cs:
namespace BlazorSessionAppState.Data
{
public class AppState
{
public bool IsAuthenticated { get; set; }
public string UserId { get; set; }
}
}
索引.剃刀:
@page "/"
@using BlazorSessionAppState.Data
@inject BlazorSessionAppState.Services.SessionStorageService SessionService
<h3>Blazor Server Session Storage Example</h3>
<p>IsAuthenticated: @_appState?.IsAuthenticated</p>
<p>UserId: @_appState?.UserId</p>
<button @onclick="SetAppState">Set State</button>
<button @onclick="GetAppState">Get State</button>
@code {
private AppState _appState;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_appState = await SessionService.GetAppStateAsync();
StateHasChanged();
}
}
private async Task SetAppState()
{
_appState = new AppState
{
IsAuthenticated = true,
UserId = "TestUser123"
};
await SessionService.SaveAppStateAsync(_appState);
}
private async Task GetAppState()
{
_appState = await SessionService.GetAppStateAsync();
StateHasChanged();
}
}
SessionStorageService.cs:
using BlazorSessionAppState.Data;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using System.Text.Json;
namespace BlazorSessionAppState.Services
{
public class SessionStorageService
{
private readonly ProtectedSessionStorage _sessionStorage;
public SessionStorageService(ProtectedSessionStorage sessionStorage)
{
_sessionStorage = sessionStorage;
}
public async Task SaveAppStateAsync(AppState appState)
{
await _sessionStorage.SetAsync("AppState", appState);
}
public async Task<AppState> GetAppStateAsync()
{
var result = await _sessionStorage.GetAsync<AppState>("AppState");
return result.Success ? result.Value : new AppState();
}
}
}
程序.cs:
builder.Services.AddScoped<SessionStorageService>(); // Register as Scoped
这里是文档链接: