Base solution for your next web application
Open Closed

Using UnitOfWorkManager in asynchronous methods #1072


User avatar
0
colinplater created

I have some code which inserts a candidate and then triggers an event to perform some other actions. Within the event there is code which should update the candidate, but it always fails because the candidate isn't being saved to the database until after the event. Here is the code:

[AbpAuthorize(RecruitmentPermissions.Recruitment_Candidates_Create)]
        protected virtual async Task CreateCandidateAsync(CandidateEditDto input, bool suppressEvents = false)
        {
            var candidate = input.MapTo<Candidate>();
            candidate.Id = Guid.NewGuid();

            if (candidate.User.TenantId == null)
            {
                Abp.Authorization.Users.UserRole userRole = new Abp.Authorization.Users.UserRole()
                {
                    RoleId = 3
                };

                candidate.User.TenantId = AbpSession.TenantId;

                candidate.User.Name = input.FirstName;
                candidate.User.Surname = input.Surname;
                candidate.User.UserName = input.Username ?? input.EmailAddress;
                candidate.User.Password = new PasswordHasher().HashPassword(input.Password);
                candidate.User.IsActive = true;
                candidate.User.EmailAddress = input.EmailAddress;
                candidate.User.Roles = new List<Abp.Authorization.Users.UserRole>()
                {
                    userRole
                };
                candidate.User.CreatorUserId = AbpSession.UserId;
            }

            // wait for insertion before firing event
            _unitOfWorkManager.Current.Completed += (sender, args) =>
            {
                if (!suppressEvents)
                    EventBus.Trigger(new InsertCandidateEventData { candidate = candidate });
            };

            await _candidateRepository.InsertAsync(candidate);

        }

According to the documentation, after InsertAsync has been run the unitOfWorkManager should then trigger my event - but it doesn't. I've tried saving manually (_unitOfWorkManager.Current.SaveChanges), and also putting the insert into it's own unit of work, but the database just isn't updated until CreateCandidateAsync has completed.

I'm quite new to ASP.Net Boilerplate, so any help anyone can give would be greatly appreciated. Thanks!


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

    Hi,

    UOW is completed after your method (CreateCandidateAsync) is completed. Then your completed handler works. This is the expected behaviour. Isn't it works like that?

  • User Avatar
    0
    colinplater created

    Hi Hikalkan. It looks like the InsertAsync is locking the database table until CreateCandidateAsync has fully completed, which means when the event tries to update the candidate it can't find it. A colleague suggested changing

    _unitOfWorkManager.Current.Completed
    

    to

    _unitOfWorkManager.Current.Disposed
    

    This ensures the event doesn't fire until after the candidate has been added to the database, but also means there is an error when attempting to update the candidate because the UserManagerProxy has been disposed of.

    Is there a way I can recreate the UserManagerProxy, or stop it from being disposed of in the first place?