Registration with email confirmation ASP .NET Core

643 Views Asked by At

I'm learning ASP .NET and I'd want to make a simple registration/login page.

I've created my public class AccountController : Controller in this way:

public class AccountController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly IEmailSender _emailSender;
    private readonly ILogger _logger;

    public AccountController(
        UserManager<ApplicationUser> userManager,
        SignInManager<ApplicationUser> signInManager,
        IEmailSender emailSender,
        ILogger<AccountController> logger)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _emailSender = emailSender;
        _logger = logger;
    }
    
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        if (ModelState.IsValid)
        {
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, set lockoutOnFailure: true
            var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
            if (result.Succeeded)
            {
                _logger.LogInformation("Utente loggato.");
                return RedirectToLocal(returnUrl);
            }
            if (result.RequiresTwoFactor)
            {
                return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
            }
            if (result.IsLockedOut)
            {
                _logger.LogWarning("User bloccato.");
                return RedirectToAction(nameof(Lockout));
            }
            else
            {
                ModelState.AddModelError(string.Empty, "Tentativo di login fallito.");
                return View(model);
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }
    
    public IActionResult Register(string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]

    public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = await _userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                _logger.LogInformation("L'utente ha creato un nuovo account con una nuova password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
                await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);

                //diallowed signin for self registration, email should be confirmed first
                //await _signInManager.SignInAsync(user, isPersistent: false);
                _logger.LogInformation("L'utente ha creato un nuovo account con una nuova password.");
                return RedirectToConfirmEmailNotification();
            }
            AddErrors(result);
        }
        return View(model);
    }
    
    public async Task<IActionResult> ConfirmEmail(string userId, string code)
    {
        if (userId == null || code == null)
        {
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }
        var user = await _userManager.FindByIdAsync(userId);
        if (user == null)
        {
            throw new ApplicationException($"Unable to load user with ID '{userId}'.");
        }
        var result = await _userManager.ConfirmEmailAsync(user, code);
        return View(result.Succeeded ? "ConfirmEmail" : "Error");
    }
}

Then I created Startup class and I've written the following method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Landing}/{action=Index}/{id?}");
    });
}

When I register a new user I can see it into the database but I don't receive any mail and I can't log in with the new user if I try.

I've watched some tutorials on YouTube about it and read the Microsoft documentation. To me it seems correct compared with what I've done, but surely I have to modify something and I don't notice it.

EDIT: this is what I've done for EmailSender and NetcoreService class:

public class EmailSender : IEmailSender
{        
    private SendGridOptions _sendGridOptions { get; }
    private INetcoreService _netcoreService { get; }
    private SmtpOptions _smtpOptions { get; }

    public EmailSender(IOptions<SendGridOptions> sendGridOptions,
        INetcoreService netcoreService,
        IOptions<SmtpOptions> smtpOptions)
    {
        _sendGridOptions = sendGridOptions.Value;
        _netcoreService = netcoreService;
        _smtpOptions = smtpOptions.Value;
    }


    public Task SendEmailAsync(string email, string subject, string message)
    {
        //send email using sendgrid via netcoreService
        _netcoreService.SendEmailBySendGridAsync(_sendGridOptions.SendGridKey,
            _sendGridOptions.FromEmail,
            _sendGridOptions.FromFullName,
            subject,
            message,
            email).Wait();
            
        return Task.CompletedTask;
    }
}

NetcoreService class:

public async Task SendEmailBySendGridAsync(string apiKey, string fromEmail, string fromFullName, string subject, string message, string email)
{
    var client = new SendGridClient(apiKey);
    var msg = new SendGridMessage()
    {
        From = new EmailAddress(fromEmail, fromFullName),
        Subject = subject,
        PlainTextContent = message,
        HtmlContent = message
    };
    msg.AddTo(new EmailAddress(email, email));
    await client.SendEmailAsync(msg);

}
0

There are 0 best solutions below