0
votes

I've managed to set up SignUp and LogIn for my project with ASP.NET Core Identity. Everything works fine but there is a small thing really bugging me.

Since it is a simple project I don't want to configure account confirmation by really sending email to the user so I'm using the default templates, the user is redirected to the Account.RegisterConfirmation where they can select a link to have the account confirmed which redirects the user to the /Identity/Account/ConfirmEmail which is a blank page with the title only. I don't like it. After selecting a link to confirm the account I'd like to redirect the user to the /Account/Login. But where do I set that up?

This is what I've tried so far: Add>New Scaffolded Item>Identity>Account/ConfirmEmail(file to override) and I now I have ConfirmEmail.cshtml.cs:

[AllowAnonymous]
    public class ConfirmEmailModel : PageModel
    {
        private readonly UserManager<IdentityUser> _userManager;

        public ConfirmEmailModel(UserManager<IdentityUser> userManager)
        {
            _userManager = userManager;
        }

        [TempData]
        public string StatusMessage { get; set; }

        public async Task<IActionResult> OnGetAsync(string userId, string code)
        {
            if (userId == null || code == null)
            {
                return RedirectToPage("/Index");
            }

            var user = await _userManager.FindByIdAsync(userId);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{userId}'.");
            }

            code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
            var result = await _userManager.ConfirmEmailAsync(user, code);
            StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
            return Page();
        }
    }

Changing return Page(); to return RedirectToPage("/Account/Login"); results in InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'Project.Areas.Identity.Pages.Account.ConfirmEmailModel'.

Where do I set up the return url to /Account/Login after the email is confirmed?

I also tried without Scaffolding and overriding Account/ConfirmEmail, in Register.cshtml.cs there is

 var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

and I tried changing returnUrl = returnUrl to returnUrl = "~/Account/Login" , it didn't work.

**** UPDATE ***

Since I don't need email confirmation for such a simple project I just added this

options.SignIn.RequireConfirmedAccount = false

to the Startup class so account confirmation nor email confirmation is needed.

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
                    .AddEntityFrameworkStores<ProjectContext>();


services.Configure<IdentityOptions>(options =>
{
    options.SignIn.RequireConfirmedEmail = false;
    options.SignIn.RequireConfirmedAccount = false;
});
1
does it works fine for return Page(); I am seeing the error message is for the DI.... - Rohit Kumar
try adding a tilde '~' to the url like return RedirectToPage("~/Account/Login") - Jonathan Alfaro
@RohitKumar I just noticed that it does not work for return Page() also, actually after Add>New Scaffolded Item>Identity>Account/ConfirmEmail(file to override) I get InvalidOperationException even if I do not make any changes to the ConfirmEmail.cshtml.cs - Yopa
@JonathanAlfaro it also doesn't work with ~ - Yopa
the error is with DI .....does the execution even reaches till var result = await _userManager.ConfirmEmailAsync(user, code); - Rohit Kumar

1 Answers

0
votes

I'm using the default templates, the user is redirected to the Account.RegisterConfirmation

In default code of configuring Identity service, we would find that RequireConfirmedAccount option is set to true, like below.

services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

And we can find that user will be redirected to RegisterConfirmation page after user account is create in RegisterModel class page handler.

if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
    return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
}
else
{

it is a simple project I don't want to configure account confirmation

If you do not need account confirmation, you could not set RequireConfirmedAccount property (defaults to false) of SignInOptions while you configure Identity service.

services.AddDefaultIdentity<ApplicationUser>()
        .AddEntityFrameworkStores<ProjectContext>();

Or as you did, set SignIn settings explicitly.

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
    .AddEntityFrameworkStores<ProjectContext>();

Besides, we can find that you call services.AddDefaultIdentity<ApplicationUser>(...) to configure Identity service with your custom ApplicationUser class in Startup ConfigureServices method, but you inject an instance of UserManager within ConfirmEmailModel class using UserManager<IdentityUser> (should use UserManager<ApplicationUser>), which cause the exception.

enter image description here