How my NormalizeEmail always null?

Nhựt Lại 65 Reputation points
2024-06-19T18:47:21.2133333+00:00

Hi, I'm new to this, so I'm not so good, your help is my pleasure.
I have a problem, when I sign up for an account, it is okay, but when I log in, as far as I know, the NormalizeEmail is always null, and I don't know why, I try to cover in the database, but its don't work either. But my UserName ( I set it as email, cause I want people to log in by their email ), is automatically Normalized, I don't know where the problem is. Can someone, help me, please? I would very very appreciate it. If you need to see any file, just comment. Thank you.

This my LoginViewModel

namespace ChatApp_BE.ViewModels { public class LoginViewModel { public string Email { get; set; } public string Password { get; set; } public bool RememberMe { get; set; } } }

Here my User Model

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ChatApp_BE.Models;
public class User : IdentityUser
{
    public string? Nickname { get; set; }
    public string Email { get; set; } = string.Empty;
    public bool EmailConfirmed { get; set; }
    public string? PasswordHash { get; set; }
    public string? SecurityStamp { get; set; }
    public string? FullName { get; set; }
    public string? Avatar { get; set; }
    public string? EmailConfirmationToken { get; set; }
    public string? ResetPasswordToken { get; set; }
    public string? RefreshToken { get; set; }
    public virtual ICollection<Message> Messages { get; set; } = new List<Message>();
    public virtual ICollection<RoomUser> RoomUsers { get; set; } = new List<RoomUser>();
    public virtual ICollection<Room> Rooms { get; set; } = new List<Room>();
}

Here is Register

[HttpPost("register")]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user != null && await _userManager.IsEmailConfirmedAsync(user))
        {
            return BadRequest("Email was already used.");
        }
        user = new User
        {
            UserName = model.Email,
            Email = model.Email,
            FullName = model.FullName,
        };
        var result = await _userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            var confirmationLink = Url.Action(
                nameof(ConfirmEmail),
                "User",
                new { userId = user.Id, token },
                Request.Scheme
                );
            await _emailSender.SendEmailAsync("Confirm your email",
                model.Email,
                $"Please confirm your email by clicking <a href=\"{confirmationLink}\">here</a>.");
            return Ok(new { Message = "Registration successful! Please check your email to confirm your account." });
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }
    return BadRequest(ModelState);
}

Here is Login.

[HttpPost("login")]
public async Task<IActionResult> Login(LoginViewModel model)
{
    try
    {
        if (ModelState.IsValid)
        {
            var normalizedEmail = _userManager.NormalizeEmail(model.Email);
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null || !await _userManager.CheckPasswordAsync(user, model.Password)) // tu lam sau nhe
            {
                return Unauthorized("Invalid login attempt.");
            }
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes(_config.GetSection("Jwt:SecretKey").Value!);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);
            return Ok(new { Token = tokenString });
        }
        return BadRequest(ModelState);
    }
    catch (Exception ex)
    {
        return BadRequest(ex.Message);
    }
}

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,390 questions
0 comments No comments
{count} votes

Accepted answer
  1. Ping Ni-MSFT 3,365 Reputation points Microsoft Vendor
    2024-06-20T09:21:02.66+00:00

    Hi @Nhựt Lại

    User.Email hides inherited member IdentityUser<string>.Email. To make the current member override that implementation, add the override keyword:

    public class User : IdentityUser
    {
        public string? Nickname { get; set; }
        public override string  Email { get; set; } = string.Empty;
        //other properties....
    }
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Rena

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. AgaveJoe 27,656 Reputation points
    2024-06-19T20:06:14.6433333+00:00

    As far as I can tell this is an Identity customization question.

    The convention for modifying the user in Identity is naming the class "ApplicationUser". "User" is a property of the ControllerBase class. Naming a class "User" and instantiating the class in a controller is not the best idea. See the docs.

    https://learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-8.0#custom-user-data

    I'm guessing the issue is "User" is not passed as an argument to the context, IdentityDbContext<User>, as illustrated in the link above.

    1 person found this answer helpful.