userManager.CreateAsync System.ObjectDisposedException non è stato gestito

asp.net-core asp.net-core-mvc asp.net-identity-3 entity-framework-core

Domanda

Stiamo cercando di utilizzare l'autenticazione dell'account Microsoft in un progetto ASP.Net 5. Non richiediamo l'autenticazione locale e non richiediamo nomi utente.

Nel modello ASP.Net 5 per un'applicazione Web, dopo aver effettuato l'accesso con un fornitore esterno, il controllo torna a ExternalLoginCallback in AccountController.

Se l'utente non è registrato localmente, ExternalLoginCallback restituisce l'utente a una schermata di registrazione. Ho tentato di modificare ExternalLoginCallback per registrare automaticamente il nuovo utente come di seguito.

        public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null)
    {
        var info = await _signInManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return RedirectToAction(nameof(Login));
        }

        // Sign in the user with this external login provider if the user already has a login.
        var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
        if (result.Succeeded)
        {
            _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
            return RedirectToLocal(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
        }
        if (result.IsLockedOut)
        {
            return View("Lockout");
        }
        else
        {
            // If the user does not have an account, then ask the user to create an account.
            //ViewData["ReturnUrl"] = returnUrl;
            //ViewData["LoginProvider"] = info.LoginProvider;
            //var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email);
            //return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });

            // The user has not previously logged in with an external provider. Create a new user.
            CreateUser(info);
            return RedirectToLocal(returnUrl);
        }
    }

CreateUser implementa il codice copiato da ExternalLoginConfirmation come appare nel modello ASP.Net 5 per un'applicazione web.

        private async void CreateUser(ExternalLoginInfo info)
    {
        var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email);
        var user = new ApplicationUser { UserName = email, Email = email };
        var result = await _userManager.CreateAsync(user);
        if (result.Succeeded)
        {
            result = await _userManager.AddLoginAsync(user, info);
            if (result.Succeeded)
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
            }
        }
        AddErrors(result);
    }

Un errore viene lanciato sulla linea

var result = await _userManager.CreateAsync(user);

L'errore è

System.ObjectDisposedException was unhandled Message: An unhandled exception of type 'System.ObjectDisposedException' occurred in mscorlib.dll. Additional information: Cannot access a disposed object.

Ho riavviato la mia macchina nel caso in cui fosse "solo una di quelle cose", ma l'errore si ripresenta.

Risposta accettata

L'uso di un metodo di async void è raramente una buona idea ed è il modo migliore per introdurre condizioni di gara strane come quella che stai vivendo: dal momento che il tuo metodo CreateUser non restituisce un'attività, non può essere atteso da ExternalLoginCallback e dalla richiesta completa prima CreateUser ha il tempo per eseguire le operazioni di database (quando la richiesta viene completata, la chiamata di sistema dI Dispose sulle dipendenze con ambito come il vostro contesto EF).

Aggiorna il tuo CreateUser metodo per restituire un Task e attendono da ExternalLoginCallback e dovrebbe funzionare:

await CreateUser(info);


Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow