无法访问已处置的对象Asp.net Identity Core

cho*_*bo2 8 c# asp.net-identity entity-framework-core asp.net-core-2.0

我收到了这个错误

System.ObjectDisposedException
  HResult=0x80131622
  Message=Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.AsyncDisposer.Dispose()
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<ExecuteSingletonAsyncQuery>d__21`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Identity.UserManager`1.<FindByNameAsync>d__78.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Identity.UserValidator`1.<ValidateUserName>d__6.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Identity.UserValidator`1.<ValidateAsync>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Identity.UserManager`1.<ValidateUserAsync>d__172.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Identity.UserManager`1.<CreateAsync>d__74.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Identity.UserManager`1.<CreateAsync>d__79.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at EmployeeController.<Create>d__3.MoveNext() in Controllers\EmployeeController.cs:line 31
Run Code Online (Sandbox Code Playgroud)

对于以下代码

public class EmployeeController : Controller
{
    private readonly UserManager<Employee> userManager;
    public EmployeeController(UserManager<Employee> userManager)
    {
        this.userManager = userManager;
    }

    public ActionResult<string> Get()
    {
        return "Test Employee";
    }

    [HttpPost("Create")]
    public async void Create([FromBody]string employee)
    {
        var user = new Employee { UserName = "test@gmail.com", Email = "test@gmail.com" };
        var d = await userManager.CreateAsync(user, "1234567");
    }
}
Run Code Online (Sandbox Code Playgroud)

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<Employee, IdentityRole>(opts =>
       {
           opts.Password.RequireDigit = false;
           opts.Password.RequireLowercase = false;
           opts.Password.RequireUppercase = false;
           opts.Password.RequireNonAlphanumeric = false;
           opts.Password.RequiredLength = 7;
           opts.User.RequireUniqueEmail = true;

       }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

        services.AddAuthentication(opts =>
        {
            opts.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(cfg =>
        {
            cfg.RequireHttpsMetadata = false;
            cfg.SaveToken = true;
            cfg.TokenValidationParameters = new TokenValidationParameters()
            {
                // standard configuration
                ValidIssuer = Configuration["Auth:Jwt:Issuer"],
                ValidAudience = Configuration["Auth:Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(Configuration["Auth:Jwt:Key"])),
                ClockSkew = TimeSpan.Zero,

                // security switches
                RequireExpirationTime = true,
                ValidateIssuer = true,
                ValidateIssuerSigningKey = true,
                ValidateAudience = true
            };
        });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseAuthentication();
        app.UseMvc();
    }
}
Run Code Online (Sandbox Code Playgroud)

我需要在我的DI中注册一些东西吗?我的印象AddEntityFrameworkStores<ApplicationDbContext>()就足够了.

SO *_*ood 28

你是async void受害者:

[HttpPost("Create")]
public async void Create([FromBody]string employee)
{
    var user = new Employee { UserName = "test@gmail.com", Email = "test@gmail.com" };
    var d = await userManager.CreateAsync(user, "1234567");
}
Run Code Online (Sandbox Code Playgroud)

您正在调度等待的异步操作,并且上下文将在await context.SaveChangesAsync()in 之前处理CreateAsync.

快速,明显的解决方案

[HttpPost("Create")]
public async Task Create([FromBody]string employee)
{
    var user = new Employee { UserName = "test@gmail.com", Email = "test@gmail.com" };
    var d = await userManager.CreateAsync(user, "1234567");
}
Run Code Online (Sandbox Code Playgroud)

但是,您应该始终IActionResult从Action 返回.这样可以更轻松地更改响应代码并显示您的意图:

[HttpPost("Create")]
public async Task<IActionResult> Create([FromBody]string employee)
{
    var user = new Employee { UserName = "test@gmail.com", Email = "test@gmail.com" };
    var d = await userManager.CreateAsync(user, "1234567");

    if (d == IdentityResult.Success)
    {
        return Ok();
    }
    else 
    {
        return BadRequest(d);
    }
}
Run Code Online (Sandbox Code Playgroud)