美文网首页角落的白板报ABP
ABPZero中的Name和SurName处理,以及EmailA

ABPZero中的Name和SurName处理,以及EmailA

作者: 角落的白板笔 | 来源:发表于2017-04-17 14:17 被阅读276次

    使用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"中添加覆盖方法,找不到的如图所示:

    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的实体验证。。
    如下图所示。

    Paste_Image.png

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

    Paste_Image.png

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

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

    相关文章

      网友评论

      • 圣杰:经常看到maliming在 abp github上活跃,提问题,英语66的。

      本文标题:ABPZero中的Name和SurName处理,以及EmailA

      本文链接:https://www.haomeiwen.com/subject/xsstzttx.html