ABPZero中的Name和SurName处理,以及EmailAddress解决方案(完美)。

简介: 使用ABPzero的朋友们都知道,User表中有Name和Surname两个字段,这两个字段对于国内的用户来说相当的不友好。以及我们的一些系统中是不会涉及到EmailAddress字段。

使用ABPzero的朋友们都知道,User表中有Name和Surname两个字段,这两个字段对于国内的用户来说相当的不友好。
以及我们的一些系统中是不会涉及到EmailAddress字段。也就是说不会使用邮箱来进行注册的,那么我们怎么解决了。

首先感谢群友https://github.com/maliming 提供的思路。

  • 在abpzero中的AbpUser实体中Name和Surname、EmailAddress都是为必填。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Abp.Configuration;
using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using Abp.Extensions;

namespace Abp.Authorization.Users
{
    /// <summary>
    /// Represents a user.
    /// </summary>
    public abstract class AbpUser<TUser> : AbpUserBase, IFullAudited<TUser>, IPassivable
        where TUser : AbpUser<TUser>
    {
        /// <summary>
        /// UserName of the admin.
        /// admin can not be deleted and UserName of the admin can not be changed.
        /// </summary>
        public const string AdminUserName = "admin";

        /// <summary>
        /// Maximum length of the <see cref="Name"/> property.
        /// </summary>
        public const int MaxNameLength = 32;

        /// <summary>
        /// Maximum length of the <see cref="Surname"/> property.
        /// </summary>
        public const int MaxSurnameLength = 32;

        /// <summary>
        /// Maximum length of the <see cref="Password"/> property.
        /// </summary>
        public const int MaxPasswordLength = 128;

        /// <summary>
        /// Maximum length of the <see cref="Password"/> without hashed.
        /// </summary>
        public const int MaxPlainPasswordLength = 32;

        /// <summary>
        /// Maximum length of the <see cref="EmailConfirmationCode"/> property.
        /// </summary>
        public const int MaxEmailConfirmationCodeLength = 328;

        /// <summary>
        /// Maximum length of the <see cref="PasswordResetCode"/> property.
        /// </summary>
        public const int MaxPasswordResetCodeLength = 328;

        /// <summary>
        /// Maximum length of the <see cref="AuthenticationSource"/> property.
        /// </summary>
        public const int MaxAuthenticationSourceLength = 64;

        /// <summary>
        /// Authorization source name.
        /// It's set to external authentication source name if created by an external source.
        /// Default: null.
        /// </summary>
        [MaxLength(MaxAuthenticationSourceLength)]
        public virtual string AuthenticationSource { get; set; }

        /// <summary>
        /// Name of the user.
        /// </summary>
        [Required]
        [StringLength(MaxNameLength)]
        public virtual string Name { get; set; }

        /// <summary>
        /// Surname of the user.
        /// </summary>
        [Required]
        [StringLength(MaxSurnameLength)]
        public virtual string Surname { get; set; }

        /// <summary>
        /// Return full name (Name Surname )
        /// </summary>
        [NotMapped]
        public virtual string FullName { get { return this.Name + " " + this.Surname; } }

        /// <summary>
        /// Password of the user.
        /// </summary>
        [Required]
        [StringLength(MaxPasswordLength)]
        public virtual string Password { get; set; }

        /// <summary>
        /// Is the <see cref="AbpUserBase.EmailAddress"/> confirmed.
        /// </summary>
        public virtual bool IsEmailConfirmed { get; set; }

        /// <summary>
        /// Confirmation code for email.
        /// </summary>
        [StringLength(MaxEmailConfirmationCodeLength)]
        public virtual string EmailConfirmationCode { get; set; }

        /// <summary>
        /// Reset code for password.
        /// It's not valid if it's null.
        /// It's for one usage and must be set to null after reset.
        /// </summary>
        [StringLength(MaxPasswordResetCodeLength)]
        public virtual string PasswordResetCode { get; set; }

        /// <summary>
        /// Lockout end date.
        /// </summary>
        public virtual DateTime? LockoutEndDateUtc { get; set; }

        /// <summary>
        /// Gets or sets the access failed count.
        /// </summary>
        public virtual int AccessFailedCount { get; set; }

        /// <summary>
        /// Gets or sets the lockout enabled.
        /// </summary>
        public virtual bool IsLockoutEnabled { get; set; }

        /// <summary>
        /// Gets or sets the phone number.
        /// </summary>
        public virtual string PhoneNumber {get; set; }

        /// <summary>
        /// Is the <see cref="AbpUser{TUser}.PhoneNumber"/> confirmed.
        /// </summary>
        public virtual bool IsPhoneNumberConfirmed { get; set; }

        /// <summary>
        /// Gets or sets the security stamp.
        /// </summary>
        public virtual string SecurityStamp { get; set; }

        /// <summary>
        /// Is two factor auth enabled.
        /// </summary>
        public virtual bool IsTwoFactorEnabled { get; set; }

        /// <summary>
        /// Is this user active?
        /// If as user is not active, he/she can not use the application.
        /// </summary>
        public virtual bool IsActive { get; set; }

        /// <summary>
        /// Login definitions for this user.
        /// </summary>
        [ForeignKey("UserId")]
        public virtual ICollection<UserLogin> Logins { get; set; }

        /// <summary>
        /// Roles of this user.
        /// </summary>
        [ForeignKey("UserId")]
        public virtual ICollection<UserRole> Roles { get; set; }

        /// <summary>
        /// Claims of this user.
        /// </summary>
        [ForeignKey("UserId")]
        public virtual ICollection<UserClaim> Claims { get; set; }

        /// <summary>
        /// Permission definitions for this user.
        /// </summary>
        [ForeignKey("UserId")]
        public virtual ICollection<UserPermissionSetting> Permissions { get; set; }

        /// <summary>
        /// Settings for this user.
        /// </summary>
        [ForeignKey("UserId")]
        public virtual ICollection<Setting> Settings { get; set; }

        public virtual TUser DeleterUser { get; set; }

        public virtual TUser CreatorUser { get; set; }

        public virtual TUser LastModifierUser { get; set; }

        protected AbpUser()
        {
            IsActive = true;
            IsLockoutEnabled = true;
            SecurityStamp = SequentialGuidGenerator.Instance.Create().ToString();
        }

        public virtual void SetNewPasswordResetCode()
        {
            PasswordResetCode = Guid.NewGuid().ToString("N").Truncate(MaxPasswordResetCodeLength);
        }

        public virtual void SetNewEmailConfirmationCode()
        {
            EmailConfirmationCode = Guid.NewGuid().ToString("N").Truncate(MaxEmailConfirmationCodeLength);
        }

        public override string ToString()
        {
            return string.Format("[User {0}] {1}", Id, UserName);
        }
    }
}

以上为ABPZERO源代码中的字段,我们怎么修改呢。

  • 修改User实体信息。
    打开我们项目中的User.cs实体。
public class User : AbpUser<User>
    {
        public const string DefaultPassword = "123qwe";

        public static string CreateRandomPassword()
        {
            return Guid.NewGuid().ToString("N").Truncate(16);
        }

         
        private new string Name { get; set; }

        private new string Surname { get; set; }

        [Required(AllowEmptyStrings = true)]
        public override string EmailAddress { get; set; }


        public static User CreateTenantAdminUser(int tenantId, string emailAddress, string password)
        {
            return new User
            {
                TenantId = tenantId,
                UserName = AdminUserName,
         Name = AdminUserName,
                Surname = AdminUserName,
                EmailAddress = emailAddress,
                Password = new PasswordHasher().HashPassword(password)
            };
        }
    }

可以看到我将Name和SurName字段设置为private,这样设置之后,就有了值对象的感觉,EF在做实体验证的时候就不会对private的属性字段进行验证。
而Emailaddress因为涉及了很多的业务情况,我们不能将它设置为私有访问。

  • 修改DbContext

我们打开'CMSDbContext.cs',添加方法

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<User>().Ignore(a => a.Name);
            modelBuilder.Entity<User>().Ignore(a => a.Surname);

            modelBuilder.Entity<User>().Property(a => a.EmailAddress).IsOptional();
            //   modelBuilder.Entity<User>().a => a.Name);

        }

覆盖方法‘OnModelCreating’,然后将Name和SurName设置为忽略。
然后将EmailAddress设置为可空。

  • 执行迁移
    然后执行迁移文件命令:"add-migration Remove_Name_SurName".
    然后再执行"update-database",生成的数据库中就不会有“Name”和“Surname”。
  • 到目前为止,Name和SurName就不影响功能使用和开发了。

EmailAddress实体字段修改

   CheckErrors(await _userManager.CreateAsync(user));

在userManager领域服务中的CreateAsync提供的方法中,检查了EmailAddress 所以我们要重写方法。

修改后的'UserManager.cs'

  public class UserManager : AbpUserManager<Role, User>
    {
        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public UserManager(
            UserStore userStore,
            RoleManager roleManager,
            IPermissionManager permissionManager,
            IUnitOfWorkManager unitOfWorkManager,
            ICacheManager cacheManager,
            IRepository<OrganizationUnit, long> organizationUnitRepository,
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
            IOrganizationUnitSettings organizationUnitSettings,
            ILocalizationManager localizationManager,
            ISettingManager settingManager,
            IdentityEmailMessageService emailService,
            IUserTokenProviderAccessor userTokenProviderAccessor, IUnitOfWorkManager unitOfWorkManager1)
            : base(
                  userStore,
                  roleManager,
                  permissionManager,
                  unitOfWorkManager,
                  cacheManager,
                  organizationUnitRepository,
                  userOrganizationUnitRepository,
                  organizationUnitSettings,
                  localizationManager,
                  emailService,
                  settingManager,
                  userTokenProviderAccessor)
        {
            _unitOfWorkManager = unitOfWorkManager1;
        }


        public override async Task<IdentityResult> CheckDuplicateUsernameOrEmailAddressAsync(long? expectedUserId, string userName, string emailAddress)
        {
            var user = (await FindByNameAsync(userName));
            if (user != null && user.Id != expectedUserId)
            {
                return AbpIdentityResult.Failed(string.Format(L("Identity.DuplicateName"), userName));
            }

         
            return IdentityResult.Success;
        }

        private string L(string name)
        {
            return LocalizationManager.GetString(AbpZeroConsts.LocalizationSourceName, name);
        }

        public override async Task<IdentityResult> CreateAsync(User user)
        {
            var result = await CheckDuplicateUsernameOrEmailAddressAsync(user.Id, user.UserName, user.EmailAddress);
            if (!result.Succeeded)
            {
                return result;
            }

            user.EmailAddress = string.Empty;

            var tenantId = GetCurrentTenantId();
            if (tenantId.HasValue && !user.TenantId.HasValue)
            {
                user.TenantId = tenantId.Value;
            }

            try
            {
                return await base.CreateAsync(user);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
         
        }

        private int? GetCurrentTenantId()
        {
            if (_unitOfWorkManager.Current != null)
            {
                return _unitOfWorkManager.Current.GetTenantId();
            }

            return AbpSession.TenantId;
        }
    }

截止以上我们的功能EmailAddress功能就算正常了。

以下为旧文,大家可以自己对比观察。

使用ABPzero的朋友们都知道,User表中有Name和Surname两个字段,这两个字段对于国内的用户来说相当的不友好。

我们在尝试了很多的方法之后,发现无法完美将他们干掉。
所以尝试使用了一个比较不友好加流氓的方式来使用它。
如果你在使用的过程有更加美好的解决方案,可以提供给我们。
以及到https://github.com/aspnetboilerplate/module-zero/issues/337 这里提出方法。

开始流程:
首先到 "CMSDbContext.cs"中添加覆盖方法,找不到的如图所示:

img_f7b0b2f272d07028faa6a961744fadbf.png
Paste_Image.png
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {  
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<User>().Ignore(a => a.Name);
            modelBuilder.Entity<User>().Ignore(a => a.Surname);       

        }

然后执行迁移文件命令:"add-migration Remove_Name_SurName".
然后再执行"update-database",生成的数据库中就不会有“Name”和“Surname”。
但是坑爹的地方就在这,我们在执行Insert(User)方法的时候还是会报错。对于这种情况。我深深的感觉到了无力(感觉身体被Kid掏空)。
没有其他办法,只能暴力解决。在方法中,默认添加Name和Surname的值,只是为了绕过Eentityframework的实体验证。。
如下图所示。

img_afeb3d2bdff03559d41d0261073e1e59.png
Paste_Image.png

这样绕过之后,发现可以正常的处理信息。

img_61c0164fbc1cb6d574c571d333ca85d6.png
Paste_Image.png

User表中的Name和Surname也不在了。唯一不友好的地方就是坑爹。。

以上算是一个坑爹解决方法。
如果你有更加友好的解决方法。联系我。

目录
相关文章
|
6月前
|
算法 Java 调度
死锁预防与解决方案
死锁预防与解决方案
|
6月前
|
前端开发 安全 JavaScript
有哪些常见的前端问题和解决方案
【4月更文挑战第13天】前端开发常见问题及解决方案:页面渲染性能优化(减少重绘、回流,利用GPU加速,代码拆分)、响应式设计(媒体查询、弹性布局)、浏览器兼容性(使用前缀,兼容性库,浏览器嗅探)、事件处理(事件委托、防抖节流)、代码组织(模块化、构建工具)、安全性(输入验证、HTTPS、安全HTTP头)和资源加载(CDN、资源优化、错误处理)。
492 6
|
Java Spring
解决方案 --[restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. ERROR 9680 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter
|
6月前
|
存储 运维 数据库
不敢书面化的解决方案就不是好方案
不敢书面化的解决方案就不是好方案
|
存储 编解码 监控
报告厅解决方案
大型单位、企业都建有报告厅,单位搭建报告厅的目的是为了召开各类会议、学术讨论、演讲、报告、新闻发布、多媒体教学培训、观看电影等活动提供卓越的音质效果、清晰的画面显示以及简单便捷的集中控制。报告厅通常会涉及举办活动时将现场画面的保存记录、活动画面以直播的形式在报告厅之外的其他屏幕上观看(因为报告厅容纳人数有限的原因)。针对这两个需求我们做了以下解决方案
|
安全 机器人 数据安全/隐私保护
开发中遇到的问题&解决方案(九)
在我们的系统里验证码是必不可少的,比如注册登录时,忘记密码时,设置支付密码时或者支付下单时,那验证码的作用在哪里呢?其实就一条为了防止来着黑客和机器人恶意的攻击,那么下面我们来看看hutool里验证码工具类。
267 0
开发中遇到的问题&解决方案(九)
|
网络协议 数据安全/隐私保护
开发中遇到的问题&解决方案(七)
邮件发送相信大家都不陌生吧,一般是用于电商平台比如京东下单后订单信息的邮件发送或者移动这种的月度账单的邮件发送,再有就是通过绑定的邮箱进行密码重置,由邮箱跳转到指定的密码重置页进行密码重置操作。那么下面我们来看看hutool里对于邮件发送的包装是怎么样的。
203 0
开发中遇到的问题&解决方案(七)
|
设计模式 前端开发 Java
开发中遇到的问题&解决方案(一)
在开发过程在我们往往会遇到很多的开发阻碍或者因为原生框架的不支持导致的一系列问题或者有的不是问题,是我们使用普通的大量的复制粘贴改改就能用的代码去实现功能,这样使得代码很冗余,我们能不能去尝试找一些好的方案比如采用设计模式这些去优化我们的代码,实现代码简洁明了,易扩展呢?答案是肯定的。这个系列文章会使用案列加解决方案的形式为大家讲解,那下面我们开始吧。
752 0
开发中遇到的问题&解决方案(一)
|
Java
开发中遇到的问题&解决方案(八)
以前的一个老项目里使用过ZXing进行会员和门店二维码的生成操作,当时出现过Java版本升级后不兼容的问题,很是麻烦,于是替换成了hutool里的二维码生成,下面我们来看看具体的实现。
201 0
开发中遇到的问题&解决方案(八)
|
人工智能 并行计算 算法
化工行业解决方案
针对化工产业的发展现状和问题,必须把绿色发展、责任关怀、包容性发 展等作为重点,整体推进全行业的转型升级和可持续发展。数字化将成为 这一转型过程的关键推动力。
化工行业解决方案