gpt4 book ai didi

c# - AddScoped 服务不会在整个请求中保留设置

转载 作者:太空宇宙 更新时间:2023-11-03 23:24:01 25 4
gpt4 key购买 nike

我已经创建了一个接口(interface)

public interface ICurrentUser
{
Task<bool> Set(UserAuth user);
User Get();
}

和一个类

public class CurrentUserSvc : Interface.ICurrentUser
{
private User _u;
private UserAuth _ua;
private AppDbContext db;

public CurrentUserSvc(AppDbContext db) {
this.db = db;
}

public User Get()
{
return _u;
}

public async Task<bool> Set(UserAuth ua)
{
_ua = ua; // this is the default EntityFramework IdentityUser
_u = await db.AppUsers // this is my applicaiton's 'extra settings'
// user used to ensure passowrd fields are
// not passed about everywhere
.Where(u => u.UserID == _ua.UserID)
.SingleAsync();
return true;
}
}

在我设置的Startup.cs

services.AddScoped<ICurrentUser, CurrentUserSvc>();
// I also add a service which will be used later in a scoped
// lifecycle (though I've also tried transient on that one)
services.AddScoped<IProductDbSvc, ProductDbSvc>();

稍后我调用了一个中间件:

    public async Task<Task> Invoke(HttpContext hc)
{
if (hc.User.Identity.IsAuthenticated) {
UserAuth iu = await _um.FindByIdAsync(hc.User.GetUserId());
await _cus.Set(iu);
}
// the values are definitely set correctly here.
// I have inspected them during debug
return _next(hc);
}

稍后我仍然尝试访问 CurrentUserSvc 的内容 我尝试通过 GET 访问当前用户

    public ProductDbSvc(AppDbContext db, ICurrentUser cu){
this.db = db;
this.cu = cu;
// the values in cu are NULL here. Get() returns null
this.CurrentUser = cu.Get();
}

但是 Get() 的结果是 null 我期望 Scoped 参数会保留在请求生命周期中较早设置的值。

我错过了什么?是否有其他方法可以确保作用域单例在整个应用程序的生命周期中保留用户数据。

更新:我创建了一个通用项目来概括说明这个问题。 https://github.com/AlexChesser/AspnetIdentitySample

您会注意到,在 DEBUG 输出中,您可以看到设置了正确的用户详细信息,但在实际 Controller 本身中,返回的值为空。

UPDATE 2 工作示例在 github https://github.com/AlexChesser/AspnetIdentitySample/tree/dependencyinjectionscoped 的这个分支上

UPDATE 3 结果表明,作用域参数也可以注入(inject)到自定义中间件的 INVOKE 方法中。 https://github.com/AlexChesser/AspnetIdentitySample/commit/25b010a5ae45678c137b2ad05c53ccd659a29101 更改调用方法将允许正确注入(inject)作用域参数。

public async Task Invoke(HttpContext httpContext,
ICurrentUserService cus,
UserManager<ApplicationUser> um)
{
if (httpContext.User.Identity.IsAuthenticated)
{
ApplicationUser au = await um.FindByIdAsync(httpContext.User.GetUserId());
await cus.Set(au);
}
await _next(httpContext);
}

更新 4 - 昨晚我发现我的中间件签名存在一个非常重要的问题。上面的代码已被编辑为正确的形式。具体方法是 Task<Task>return _next(...)

这导致某些页面加载时出现“白屏”死机(异步调用错误不会抛出堆栈跟踪)

通过更改为 Task 并使用 await next(...),代码可以正常运行并消除因 dotnet5 中异步实现不当而导致的间歇性白屏死机。

最佳答案

DbContext 是范围服务,您的 CurrentUserSvc 也是范围服务。中间件在应用程序的整个运行时间内只被实例化一次,所以它们本质上是单例的。因此,您需要将 DbContextCurrentUserSvc 都从此处注入(inject)的构造函数中移除。

相反,您可以使用 HttpContextRequestServices 属性(它返回一个 IServiceProvider)来解析 DbContextCurrentUserSvc 服务。

关于c# - AddScoped 服务不会在整个请求中保留设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34388790/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com