如何使用EF核心验证执行独特的实体

发布于 2025-02-07 14:15:37 字数 9257 浏览 2 评论 0原文

在注册新用户时,我提供各种字段。我想通过我的register.cshtml.cs类中的验证使电话号码唯一。

在EF中,他们使电子邮件与众不同,但我不明白如何。

我的register.cshtml.cs文件

 //[AllowAnonymous]
//[Authorize(Roles = StaticDetails.AdminEndUser)]
public class RegisterModel : PageModel
{
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly UserManager<IdentityUser> _userManager;
    private readonly ILogger<RegisterModel> _logger;

    ////comented the Iemailsender because its causing error.
    // private readonly IEmailSender _emailSender;

    //// added by me for dependency injection;
    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly ApplicationDbContext _db;

    
    public RegisterModel(
        UserManager<IdentityUser> userManager,
        SignInManager<IdentityUser> signInManager,
        ILogger<RegisterModel> logger,
        // IEmailSender emailSender,
        ////added by me for constructor for the upper used dependency injection;
        RoleManager<IdentityRole> roleManager,
        ApplicationDbContext db)
        
        
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _logger = logger;
        // _emailSender = emailSender;
        ////added by me for upper used constructor;
        _roleManager = roleManager;
        _db = db;

    }

    [BindProperty]
    public InputModel Input { get; set; }

    public string ReturnUrl { get; set; }

    public IList<AuthenticationScheme> ExternalLogins { get; set; }

    public class InputModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        //added by me

        //[BindProperty]
        //public string Gender { get; set; }
        //public string[] Genders = new[] { "Male", "Female", "Unspecified" };

        //[DataType(DataType.Date)]
        //[Column(TypeName = "Date")]
        //public DateTime DateOfBirth { get; set; }

        [Required]
       
        //public string FullName { get; set; }
        public string FirstName { get; set; }

        public string LastName { get; set; }
        public string EmployeCode { get; set; }
        public string Designation { get; set; }

        //[DataType(DataType.Date)]
        //[Column(TypeName = "Date")]
        [BindProperty]
        public DateTime DateOfBirth { get; set; }
        [BindProperty]
        public DateTime DateOfJoining { get; set; }
        public string EmergencyNo { get; set; }
        public string AdharNo { get; set; }
       
        public string Address { get; set; }
        public string City { get; set; }
        public string PostalCode { get; set; }

        [Required]
        [Display(Name = "Phone Number")]
        [MaxLength(10)]
        public string PhoneNumber { get; set; }
    }

    public async Task OnGetAsync(string returnUrl = null)
    {
        ReturnUrl = returnUrl;
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
    }

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        if (ModelState.IsValid)
        {
            //// var user = new Identityuser { UserName = Input.Email, Email = Input.Email };...I edited it because in Applicationuser class i am putting the name,address,city,postal code.
            var user = new ApplicationUser
            { 
                UserName = Input.Email, 
                Email = Input.Email ,
                FirstName = Input.FirstName,
                LastName = Input.LastName,
                EmployeCode = Input.EmployeCode,
                Designation = Input.Designation,
                //DateOfBirth= Convert.ToDateTime("DateOfBirth"),
                DateOfBirth = Input.DateOfBirth,
                DateOfJoining = Input.DateOfJoining,
                EmergencyNo = Input.EmergencyNo,
                AdharNo = Input.AdharNo,
                Address = Input.Address,
                City = Input.City,
                PostalCode = Input.PostalCode,
                PhoneNumber = Input.PhoneNumber
                
            };

            
            ////after dependency injection we come to after post handler.and in below line they r creating the user.
            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                ////added by me if this is successful we want chk if role exits in the detabase.
                ////if admin user doesnot exits we want to creat it.
                ////StaticDetails class SD created by me.
                if (!await _roleManager.RoleExistsAsync(StaticDetails.AdminEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.AdminEndUser));
                }

                if (!await _roleManager.RoleExistsAsync(StaticDetails.HrEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.HrEndUser));
                }

                if (!await _roleManager.RoleExistsAsync(StaticDetails.ItEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.ItEndUser));
                }
                if (!await _roleManager.RoleExistsAsync(StaticDetails.EmployeeEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.EmployeeEndUser));
                }

                ////roles are created now have to assign it to a user.
                ////adminuser for now.means when i will creat it will by default take adminuser.
                await _userManager.AddToRoleAsync(user, StaticDetails.EmployeeEndUser);


                _logger.LogInformation("User created a new account with password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                    protocol: Request.Scheme);

                // await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                //   $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
                
                if (_userManager.Options.SignIn.RequireConfirmedAccount)
                {
                    return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                }
                else
                {
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    return LocalRedirect(returnUrl);
                }
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}

和我的applicationdbcontext.cs类

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
   
    public DbSet<ApplicationUser> ApplicationUser { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ApplicationUser>()
            .HasIndex(a => new { a.PhoneNumber, a.EmergencyNo })
            .IsUnique(true);
    }
}

我也想使我的应用程序userclass中存在的其他属性独特:

     public string FirstName { get; set; }
    
     public string LastName { get; set; }

     public string EmployeCode { get; set; }

     public string Designation { get; set; }

     public DateTime DateOfBirth { get; set; }

     public DateTime  DateOfJoining { get; set; }

     public string EmergencyNo { get; set; }

     public string AdharNo { get; set; }

    /*
   //Department dropdown and city and country thing
   //public string Gender { get; set; }
   //public string[] Genders = new[] { "Male", "Female", "Unspecified" };
    */  //public string FullName { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string PostalCode { get; set; }

While registering a new user, I provide various fields. I want to make Phone Number unique via validation which is present in my Register.cshtml.cs class.

In EF they have made Email unique, but I can't understand how.

My Register.cshtml.cs file

 //[AllowAnonymous]
//[Authorize(Roles = StaticDetails.AdminEndUser)]
public class RegisterModel : PageModel
{
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly UserManager<IdentityUser> _userManager;
    private readonly ILogger<RegisterModel> _logger;

    ////comented the Iemailsender because its causing error.
    // private readonly IEmailSender _emailSender;

    //// added by me for dependency injection;
    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly ApplicationDbContext _db;

    
    public RegisterModel(
        UserManager<IdentityUser> userManager,
        SignInManager<IdentityUser> signInManager,
        ILogger<RegisterModel> logger,
        // IEmailSender emailSender,
        ////added by me for constructor for the upper used dependency injection;
        RoleManager<IdentityRole> roleManager,
        ApplicationDbContext db)
        
        
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _logger = logger;
        // _emailSender = emailSender;
        ////added by me for upper used constructor;
        _roleManager = roleManager;
        _db = db;

    }

    [BindProperty]
    public InputModel Input { get; set; }

    public string ReturnUrl { get; set; }

    public IList<AuthenticationScheme> ExternalLogins { get; set; }

    public class InputModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        //added by me

        //[BindProperty]
        //public string Gender { get; set; }
        //public string[] Genders = new[] { "Male", "Female", "Unspecified" };

        //[DataType(DataType.Date)]
        //[Column(TypeName = "Date")]
        //public DateTime DateOfBirth { get; set; }

        [Required]
       
        //public string FullName { get; set; }
        public string FirstName { get; set; }

        public string LastName { get; set; }
        public string EmployeCode { get; set; }
        public string Designation { get; set; }

        //[DataType(DataType.Date)]
        //[Column(TypeName = "Date")]
        [BindProperty]
        public DateTime DateOfBirth { get; set; }
        [BindProperty]
        public DateTime DateOfJoining { get; set; }
        public string EmergencyNo { get; set; }
        public string AdharNo { get; set; }
       
        public string Address { get; set; }
        public string City { get; set; }
        public string PostalCode { get; set; }

        [Required]
        [Display(Name = "Phone Number")]
        [MaxLength(10)]
        public string PhoneNumber { get; set; }
    }

    public async Task OnGetAsync(string returnUrl = null)
    {
        ReturnUrl = returnUrl;
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
    }

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        if (ModelState.IsValid)
        {
            //// var user = new Identityuser { UserName = Input.Email, Email = Input.Email };...I edited it because in Applicationuser class i am putting the name,address,city,postal code.
            var user = new ApplicationUser
            { 
                UserName = Input.Email, 
                Email = Input.Email ,
                FirstName = Input.FirstName,
                LastName = Input.LastName,
                EmployeCode = Input.EmployeCode,
                Designation = Input.Designation,
                //DateOfBirth= Convert.ToDateTime("DateOfBirth"),
                DateOfBirth = Input.DateOfBirth,
                DateOfJoining = Input.DateOfJoining,
                EmergencyNo = Input.EmergencyNo,
                AdharNo = Input.AdharNo,
                Address = Input.Address,
                City = Input.City,
                PostalCode = Input.PostalCode,
                PhoneNumber = Input.PhoneNumber
                
            };

            
            ////after dependency injection we come to after post handler.and in below line they r creating the user.
            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                ////added by me if this is successful we want chk if role exits in the detabase.
                ////if admin user doesnot exits we want to creat it.
                ////StaticDetails class SD created by me.
                if (!await _roleManager.RoleExistsAsync(StaticDetails.AdminEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.AdminEndUser));
                }

                if (!await _roleManager.RoleExistsAsync(StaticDetails.HrEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.HrEndUser));
                }

                if (!await _roleManager.RoleExistsAsync(StaticDetails.ItEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.ItEndUser));
                }
                if (!await _roleManager.RoleExistsAsync(StaticDetails.EmployeeEndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(StaticDetails.EmployeeEndUser));
                }

                ////roles are created now have to assign it to a user.
                ////adminuser for now.means when i will creat it will by default take adminuser.
                await _userManager.AddToRoleAsync(user, StaticDetails.EmployeeEndUser);


                _logger.LogInformation("User created a new account with password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                    protocol: Request.Scheme);

                // await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                //   
quot;Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
                
                if (_userManager.Options.SignIn.RequireConfirmedAccount)
                {
                    return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                }
                else
                {
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    return LocalRedirect(returnUrl);
                }
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}

and my ApplicationDbContext.cs class

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
   
    public DbSet<ApplicationUser> ApplicationUser { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ApplicationUser>()
            .HasIndex(a => new { a.PhoneNumber, a.EmergencyNo })
            .IsUnique(true);
    }
}

I also want to make some other properties unique which are present in my ApplicationUserClass:

     public string FirstName { get; set; }
    
     public string LastName { get; set; }

     public string EmployeCode { get; set; }

     public string Designation { get; set; }

     public DateTime DateOfBirth { get; set; }

     public DateTime  DateOfJoining { get; set; }

     public string EmergencyNo { get; set; }

     public string AdharNo { get; set; }

    /*
   //Department dropdown and city and country thing
   //public string Gender { get; set; }
   //public string[] Genders = new[] { "Male", "Female", "Unspecified" };
    */  //public string FullName { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string PostalCode { get; set; }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烦人精 2025-02-14 14:15:37

为此,您可以进行自定义或个性化验证。并使用该自定义属性装饰您的属性。

MobileNiqueAttribute.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using Base.Models;

namespace Core.Models
{
    public class MobileUniqueAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(
            object value, ValidationContext validationContext)
        {
            var _context = (ApplicationDbContext)validationContext.GetService(typeof(ApplicationDbContext));
            var entity = _context.RegistationTable.SingleOrDefault(e => e.PhoneNumber == value.ToString());

            if (entity != null)
            {
                return new ValidationResult(GetErrorMessage(value.ToString()));
            }
            return ValidationResult.Success;
        }

        public string GetErrorMessage(string mobile)
        {
            return $"Mobile {mobile} is already in use.";
        }
    }
}

InputModel.cs

public class InputModel
{
    [Required]
    [MobileUnique]
    public string PhoneNumber { get; set; }
}

(例如MobileniqueatTribute.cs),您也可以为其他字段创建单独的自定义验证。

For this, you can make a custom or personalized validation. and decorate your property with that custom attribute.

MobileUniqueAttribute.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using Base.Models;

namespace Core.Models
{
    public class MobileUniqueAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(
            object value, ValidationContext validationContext)
        {
            var _context = (ApplicationDbContext)validationContext.GetService(typeof(ApplicationDbContext));
            var entity = _context.RegistationTable.SingleOrDefault(e => e.PhoneNumber == value.ToString());

            if (entity != null)
            {
                return new ValidationResult(GetErrorMessage(value.ToString()));
            }
            return ValidationResult.Success;
        }

        public string GetErrorMessage(string mobile)
        {
            return 
quot;Mobile {mobile} is already in use.";
        }
    }
}

InputModel.cs

public class InputModel
{
    [Required]
    [MobileUnique]
    public string PhoneNumber { get; set; }
}

Like MobileUniqueAttribute.cs, you can create separate custom validation for other fields too.

我纯我任性 2025-02-14 14:15:37

更新startup.cs类的configureservices()方法,以添加下面的 endentityOptions services.configure&lt; dendientityOptions&gt;() method中的类属性。例如已需要UniqueEmail属性,设置一个标志,指示该应用程序是否需要为其用户提供唯一的电子邮件。

    services.Configure<IdentityOptions>(opts => {
            opts.User.RequireUniqueEmail = true; 
                   ...
               });

但是,如果您希望其他属性独特,则自定义属性是一种方式,另一种方法是使用 uservalidator 类,您可以参考以下代码,

 public class CustomUsernameEmailPolicy : UserValidator<AppUser>
    {
        public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user)
        {
            IdentityResult result = await base.ValidateAsync(manager, user);
            List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
 
            if (user.UserName == "google")
            {
                errors.Add(new IdentityError
                {
                    Description = "Google cannot be used as a user name"
                });
            }
 
            if (!user.Email.ToLower().EndsWith("@yahoo.com"))
            {
                errors.Add(new IdentityError
                {
                    Description = "Only yahoo.com email addresses are allowed"
                });
            }
            return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
        }
    }

然后在启动类的configureservices()方法中注册customusernamemailpolicy类。

 services.AddTransient<IUserValidator<AppUser>, CustomUsernameEmailPolicy>();

Update the ConfigureServices() method of the Startup.cs class to add the below IdentityOptions class properties inside the services.Configure<IdentityOptions>()method . Such as UserOptions has RequireUniqueEmail Property, sets a flag indicating whether the application requires unique emails for its users.

    services.Configure<IdentityOptions>(opts => {
            opts.User.RequireUniqueEmail = true; 
                   ...
               });

But if you want other property unique ,custom attribute is a way, another way is using the UserValidator class, you can refer to the below code

 public class CustomUsernameEmailPolicy : UserValidator<AppUser>
    {
        public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user)
        {
            IdentityResult result = await base.ValidateAsync(manager, user);
            List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
 
            if (user.UserName == "google")
            {
                errors.Add(new IdentityError
                {
                    Description = "Google cannot be used as a user name"
                });
            }
 
            if (!user.Email.ToLower().EndsWith("@yahoo.com"))
            {
                errors.Add(new IdentityError
                {
                    Description = "Only yahoo.com email addresses are allowed"
                });
            }
            return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
        }
    }

then register the CustomUsernameEmailPolicy class in the ConfigureServices() method of the Startup class.

 services.AddTransient<IUserValidator<AppUser>, CustomUsernameEmailPolicy>();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文