userManager.CreateAsync System.ObjectDisposedException no fue manejado

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

Pregunta

Estamos tratando de usar la autenticación de cuenta de Microsoft en un proyecto ASP.Net 5. No requerimos autenticación local y no requerimos nombres de usuarios.

En la Plantilla ASP.Net 5 para una aplicación web, después de iniciar sesión con un proveedor externo, el control regresa a ExternalLoginCallback en el AccountController.

Si el usuario no está registrado localmente, ExternalLoginCallback devuelve al usuario a una pantalla de registro. He intentado modificar ExternalLoginCallback para registrar automáticamente al nuevo usuario como se muestra a continuación.

        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 el código copiado de ExternalLoginConfirmation tal como aparece en la Plantilla ASP.Net 5 para una aplicación web.

        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);
        }
    }

Se lanza un error en la línea.

        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);
        }
    }

El error es

        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);
        }
    }

He reiniciado mi máquina en caso de que fuera 'solo una de esas cosas', pero el error se repite.

Respuesta aceptada

Usar un método de async void rara vez es una buena idea y es la mejor manera de introducir condiciones de carrera extrañas como la que está experimentando: dado que su método CreateUser no devuelve una tarea, ExternalLoginCallback y la solicitud no la pueden esperar. finaliza antes de que CreateUser tenga el tiempo para ejecutar las operaciones de la base de datos (cuando se completa la solicitud, la llamada del sistema DI Dispose en dependencias de ámbito como su contexto EF).

Actualice su método CreateUser para devolver una Task y esperar desde ExternalLoginCallback y debería funcionar:

await CreateUser(info);



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué