gpt4 book ai didi

c# - UserManager.ResetPasswordAsync 上出现“无法访问已处置的对象”错误

转载 作者:太空狗 更新时间:2023-10-30 01:32:27 26 4
gpt4 key购买 nike

执行 userManager.ResetPasswordAsync 时出现以下错误:

An unhandled exception occurred while processing the request.

ObjectDisposedException: Cannot access a disposed object.
Object name: 'TestDb'.
Microsoft.Data.Entity.DbContext.get_ServiceProvider()

我简化了代码以使其更易于阅读。我在 Controller 生命周期内调用了两次 userManager。一次用于生成 token ,一次用于重置密码:

    private readonly UserManager<ApplicationUser> userManager;

// controller's constructor
public AuthController(UserManager<ApplicationUser> userManager) {
this.userManager = userManager;
}

[AllowAnonymous, HttpPost]
public async Task<ActionResult> ForgotPass(ForgotPassViewModel model) {
//model checks

var user = new UserQuery(db).GetUserByUserName(model.UserName);

//check if user exists

var token = await userManager.GeneratePasswordResetTokenAsync(user);
var url = $"{config.Url}/auth/resetpass?user={user.Id}&token={WebUtility.UrlEncode(token)}";

// send email with the reset url

model.Success = "An email has been sent to your email address";
return View(model);
}

[AllowAnonymous, HttpPost]
public async Task<ActionResult> ResetPass(ResetPassViewModel model) {
//model checks

var user = new UserQuery(db).GetUserById(model.UserId);

//error occurs here:
var result = await userManager.ResetPasswordAsync(user, model.Token, model.Password);

//check result

model.Success = "Password successfully reset";
return View(model);
}

稍后编辑:这是 UserQuery 的一个函数(按照下面评论中的要求)。我确实在使用“使用”包装器:

    public ApplicationUser GetUserByUserName(string userName) {
using (var db = this.dbContext) {
var user = (from u in db.Users
where u.UserName == userName
select u).SingleOrDefault();
return user;
}
}

最佳答案

using 结构是围绕

的语法糖
DbContext context = null;
try
{
context = new DbContext();
...stuff inside the using block ...
}
finally
{
if(context!=null)
context.Dispose()
}

和调用一样

using(DbContext context = new DbContext()) 
{
...stuff inside the using block ...
}

阻止。这确保了对象被尽快释放,甚至在发生异常时也是如此(finally block 总是被调用)。

ASP.NET Core 中的 DbContext(特别是它的 ASP.NET Core Identity 注册)被注册为具有作用域的生命周期,这意味着在持续时间内将返回相同的引用的一个请求。

但是当您在请求结束前过早地处置它(使用 using block 或通过自己调用 .Dispose() 方法)时,它会在另一个方法尝试时爆炸访问它。

范围内的生命周期是推荐的,因为 DbContext 在生命周期很长时会使用大量内存,因为 DbContext 会跟踪所有记录的更改,直到您处置它。

因此,在没有依赖注入(inject)或简单教程的传统应用程序中,您可以使用 new 创建它并尽快处理它。但是在 Web 应用程序中,请求的生命周期非常短暂,并且范围内的生命周期可以处理大多数情况。可能存在一些极端情况,其中 transient (ASP.NET Core IoC 容器中的 AddTransient 方法)生命周期更好。

如果您真的需要 transient 解析,您可以创建一个工厂方法并将其注入(inject)到您的服务中,例如:

services.AddTransient<Func<MyDbContext>>( (provider) => new Func<MyDbContext>( () => new MyDbContext()));

并将其注入(inject)到您的服务/ Controller 中:

public class MyService 
{
public readonly Func<MyDbContext> createMyContext;

public MyService(Func<MyDbContext> contextFactory)
{
this.createContext = contextFactory;
}

public User GetUserById(Guid userId)
{
// note we're calling the delegate here which
// creates a new instance every time
using(var context = createContext())
{
return context.User.FirstOrDefault(u => u.Id = userId);
}
}
}

这不会导致问题,但比必要的更复杂。如果您需要交易,这可能不会很好地发挥作用,因为交易是针对每个 DbContext 实例的,而 Identity 将始终使用范围内的交易

关于c# - UserManager.ResetPasswordAsync 上出现“无法访问已处置的对象”错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37291981/

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