在尝试使用在_Host.cshtml文件中初始化的范围服务时,我遇到了一种奇怪的行为。这是一个非常简单的服务:
public interface IUserSessionService
{
void SetUserData(UserSessionData userData);
UserSessionData GetUserData();
}
public class UserSessionService : IUserSessionService
{
private UserSessionData userSessionData;
public void SetUserData(UserSessionData userData)
{
userSessionData = userData;
}
public UserSessionData GetUserData()
{
return userSessionData;
}
}该服务在Startup.cs文件中注册为作用域服务。
services.AddScoped<IUserSessionService, UserSessionService>();该服务以以下方式在host.cshtml页面后面的代码中从数据库中获取用户信息:
public class _Host : PageModel
{
private readonly IUserSessionService userSessionService;
public _Host(IUserSessionService userSessionService)
{
this.userSessionService = userSessionService;
}
public async Task OnGet()
{
var authenticatedUser = Request.HttpContext.User;
var userData = await GetUserDataFromDb(authenticatedUser);
await userSessionService.SetUserData(userData);
}
}理想情况下,我希望这将初始化服务,以便从现在起,我可以将其注入组件中,并在需要时访问用户的信息。
但是,这是行不通的:当页面加载时,我能够在屏幕上看到用户信息一秒钟,然后它就消失了。最初我认为这是由页面呈现模式ServerPrerendered引起的,但是在Server模式下问题仍然存在。
我能找到的唯一解决办法是将服务注册为Singleton;这并不理想,因为这将在所有用户之间共享(至少这是我的理解!)
有更好的地方可以储存这些信息吗?
更新
这个问题的主要原因是我对Blazor电路的理解不好:)我让它按照@enet的建议工作。我所做的是:
_Host.cshtml创建的HostModel类中从HttpContext获取信息,并将其提供给带有属性的html代码。
public class HostModel : PageModel
{
public UserSessionData UserSessionData { get; private set; }
// ... set the information up
}@model HostModel
<component type="typeof(App)" render-mode="ServerPrerendered" param-UserSessionData="@Model.UserSessionData" />App.razor中的
[Parameter]的形式访问信息@code {
[Parameter]
public UserSessionData UserSessionData { get; set; }
}OnInitializedAsync()方法中的作用域服务中设置信息。
protected override async Task OnInitializedAsync()
{
await UserSessionService.SetUserData(UserSessionData);
}现在,通过注入UserSessionData,应用程序中的任何地方都可以使用IUserSessionService。
发布于 2021-03-22 19:32:41
你不应该像你提到的那样使用Singleton。
做public async Task OnGetAsync()而不是public async Task OnGet()
将数据传递给Blazor应用程序的推荐方法是通过组件html标记助手提供的参数.
参见complete sample如何在这里这样做
注意:文档中还有一个代码示例,说明如何做到这一点。它或多或少和我的一样
更新:
下面是我曾经创建的服务。效果很好。将其与您所做的进行比较,或者更好地使用它,因为它实际上在很大程度上完成了您的服务。
UserEditService.cs
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Security.Claims;
public class UserEditService
{
private readonly AuthenticationStateProvider authProvider;
private readonly UserManager<IdentityUser> userManager;
public UserEditService ( AuthenticationStateProvider
authProvider,
UserManager<IdentityUser> userManager)
{
// Execute only when the app is served. The app is served
// when it is initially accessed, or after a user has logged-in
this.authProvider = authProvider;
this.userManager = userManager;
}
public async Task<string> GetEmail()
{
var authenticationStateTask = await
authProvider.GetAuthenticationStateAsync();
var user = authenticationStateTask.User;
// Executed whenever the GetMail method is called
if (user.Identity.IsAuthenticated)
{
// Executed only when the user is authenticated
var userId = user.Claims.Where(c => c.Type ==
ClaimTypes.NameIdentifier).FirstOrDefault();
var applicationUser = await
userManager.FindByIdAsync(userId.Value);
return applicationUser.Email;
}
return "User not authenticated";
}
} Startup.ConfigureServices
services.AddScoped<UserManager<IdentityUser>>();
services.AddScoped<UserEditService>();用法
@page "/"
@inject UserEditService UserEditService
<div>Your email: @email</div>
@code
{
private string email;
protected override async Task OnInitializedAsync()
{
email = await UserEditService.GetEmail();
}
}注意:在我的服务中,我只返回电子邮件字段,但您当然可以返回完整的身份用户.
发布于 2021-03-22 20:49:11
我不能回答你的问题,但我可以说,当涉及到使用身份验证和服务时,事情变得有点危险。我尝试了一种类似的方法:创建一个基于身份验证的返回用户信息的服务,然后将它注入到任何需要它的控件中--有时一个页面上的多个组件在初始化时访问成员身份。
这导致了很多冲突--试图在DbContext已经打开的时候访问它,等等。基本上,种族条件崩溃。
我的建议是根本不做这件事。但如果你找到一个可行的解决方案,我期待着看到它。
https://stackoverflow.com/questions/66752175
复制相似问题