Base solution for your next web application
Open Closed

Prevent Duplication without using unique Index #1672


User avatar
0
moustafa created

Hello i want to know the mechanism used to prevent duplication of username and email address in ABP , i noticed that no unique index was used for them so how does it work , how can i do the same for mobile field in the same way , i don't want to duplicate the same mobile number in the same tenant that's why i don't need to use unique index thank you


8 Answer(s)
  • User Avatar
    0
    hikalkan created
    Support Team

    Hi,

    It's done in the domain layer, in UserManager class: <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero/blob/dev/src/Abp.Zero/Authorization/Users/AbpUserManager.cs#L611">https://github.com/aspnetboilerplate/mo ... er.cs#L611</a> This method is called before create and update a user (in create: <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero/blob/dev/src/Abp.Zero/Authorization/Users/AbpUserManager.cs#L119">https://github.com/aspnetboilerplate/mo ... er.cs#L119</a>) So, you can override CreateAsync and UpdateAsync methods in your UserManager and check uniqueness.

  • User Avatar
    0
    moustafa created

    Thank you for your reply i have a further questions and i appreciate your help

    in UserManager i overrided CreateAsync Method then added CheckDuplicateMobileAsync Method

    public override async Task<IdentityResult> CreateAsync(User user)
            {
                var result = await CheckDuplicateMobileAsync(user.Id, user.Mobile);
                if (!result.Succeeded)
                {
                    return result;
                }
                return await base.CreateAsync(user);
            }
    
            public virtual async Task<IdentityResult> CheckDuplicateMobileAsync(long? expectedUserId, string mobile)
            {
               var user = (await FindByMobileAsync(mobile));  ////////////////////// This line
                if (user != null && user.Id != expectedUserId)
                {
             return AbpIdentityResult.Failed(string.Format(L("Identity.DuplicateMobile"), mobile));  /////////////// This line
                }
    
                return IdentityResult.Success;
            }
    

    in UserStore

    public class UserStore : AbpUserStore<Role, User>
        {
            private readonly IRepository<User, long> _userRepository;
            public UserStore(
                IRepository<User, long> userRepository,
                IRepository<UserLogin, long> userLoginRepository,
                IRepository<UserRole, long> userRoleRepository,
                IRepository<Role> roleRepository,
                IRepository<UserPermissionSetting, long> userPermissionSettingRepository,
                IUnitOfWorkManager unitOfWorkManager
                )
                : base(
                    userRepository,
                    userLoginRepository,
                    userRoleRepository,
                    roleRepository,
                    userPermissionSettingRepository,
                    unitOfWorkManager
                )
            {
                _userRepository = userRepository;
            }
    
            // Umbrella
    
            public virtual async Task<User> FindByMobileAsync(string mobile)
            {
                return await _userRepository.FirstOrDefaultAsync(
                    user => user.Mobile == mobile
                    );
            }
        }
    

    1- FindByMobileAsync is not exists in current context ???? 2- CS0103 The name 'L' does not exist in the current context ???

    what is wrong with my code ?

  • User Avatar
    0
    hikalkan created
    Support Team
    1. You declared FindByMobileAsync in UserStore, but using it like you defined in UserManager. I suggest you to to move it to UserManager.
    2. L is a method defined in application services and not in UserManager. Use ILocalizationManager to use localization (see docs: <a class="postlink" href="http://www.aspnetboilerplate.com/Pages/Documents/Localization#DocInServer">http://www.aspnetboilerplate.com/Pages/ ... ocInServer</a>)
  • User Avatar
    0
    moustafa created

    Actually i tried to move it to UserManager.cs but i counted a problem in userrepository injection

  • User Avatar
    0
    hikalkan created
    Support Team

    Yo don't have to pass repository to the base class since it does not wait for such an argument. Instead, assign it to a private fields in UserManager and use it in your methods (just like other simple dependency injections).

  • User Avatar
    0
    moustafa created

    i'm sorry if i bothering you with my questions actually i tried the following UserManager

    private readonly IRepository<User, long> _userRepository;
    
    
        public virtual async Task<User> FindByMobileAsync(string mobile)
            {
                return await _userRepository.FirstOrDefaultAsync(
                    user => user.Mobile == mobile
                    );
            }
    

    i got error because _userRepository is null what i missing here ?

    then what shall i do also to use L Method in usermanager ? can you please provide me a piece of code to help in my situation ? thank you

  • User Avatar
    0
    hikalkan created
    Support Team

    Hi,

    Inject IRepository<User, long> from your constructor and assign to the _userRepository field. (This is really very simple dependency injection - <a class="postlink" href="http://www.aspnetboilerplate.com/Pages/Documents/Dependency-Injection#DocResolveConstAndProp">http://www.aspnetboilerplate.com/Pages/ ... nstAndProp</a> - you probably misundertood my, otherwise you could easily do it :))

    Forget about L method. Just inject ILocalizationManager into UserManager (as the repository) and use GetString method like defined here: <a class="postlink" href="http://www.aspnetboilerplate.com/Pages/Documents/Localization#DocGetText">http://www.aspnetboilerplate.com/Pages/ ... DocGetText</a> Your source name is defined in YourProjectConsts class and you can use it like YourProjectConsts.LocalizationSourceName.

  • User Avatar
    0
    moustafa created

    Thank you now it's working just fine