Open Closed

No Tenant Context in AccountIdentityUserCreatedEventHandler when using RabbitMQ #10113


User avatar
0
amansharma created
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Identity;
using Volo.Abp.Identity.Settings;
using Volo.Abp.Settings;

namespace Volo.Abp.Account.Emailing;

public class AccountIdentityUserCreatedEventHandler :
    IDistributedEventHandler<IdentityUserCreatedEto>,
    ITransientDependency
{
    protected IdentityUserManager UserManager { get; }
    protected IAccountEmailer AccountEmailer { get; }
    protected ISettingProvider SettingProvider { get; }

    public AccountIdentityUserCreatedEventHandler(
        IdentityUserManager userManager,
        IAccountEmailer accountEmailer,
        ISettingProvider settingProvider)
    {
        UserManager = userManager;
        AccountEmailer = accountEmailer;
        SettingProvider = settingProvider;
    }

    public async Task HandleEventAsync(IdentityUserCreatedEto eventData)
    {
        if (eventData.Properties["SendConfirmationEmail"] == true.ToString().ToUpper() &&
            await SettingProvider.IsTrueAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail))
        {
            var user = await UserManager.GetByIdAsync(eventData.Id);
            var confirmationToken = await UserManager.GenerateEmailConfirmationTokenAsync(user);
            await AccountEmailer.SendEmailConfirmationLinkAsync(user, confirmationToken,
                eventData.Properties.GetOrDefault("AppName") ?? "MVC");
        }
    }
}

This code doesn't work when using RabbitMQ, because there is no tenant context here when i do it will InMemory then it works but when i add rabbitmq it is not fetching SettingProvider.IsTrueAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail) because it using null tenant context.

Is there a quick fix for this also are there any similar issue like this?


2 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    1. Solution
    • Root cause: When using the distributed event bus (RabbitMQ), the handler runs in a background consumer without an HTTP scope, so there is no ambient tenant set automatically. IdentityUserCreatedEto contains TenantId; you must set the tenant context for the duration of your handler to resolve tenant-scoped services/settings correctly.

    • Quick fix (wrap the handler body in ICurrentTenant.Change):

    using Volo.Abp.MultiTenancy;
    
      public class AccountIdentityUserCreatedEventHandler :
          IDistributedEventHandler<IdentityUserCreatedEto>,
          ITransientDependency
      {
          protected IdentityUserManager UserManager { get; }
          protected IAccountEmailer AccountEmailer { get; }
          protected ISettingProvider SettingProvider { get; }
          protected ICurrentTenant CurrentTenant { get; }
    
          public AccountIdentityUserCreatedEventHandler(
              IdentityUserManager userManager,
              IAccountEmailer accountEmailer,
              ISettingProvider settingProvider,
              ICurrentTenant currentTenant)
          {
              UserManager = userManager;
              AccountEmailer = accountEmailer;
              SettingProvider = settingProvider;
              CurrentTenant = currentTenant;
          }
    
          public async Task HandleEventAsync(IdentityUserCreatedEto eventData)
          {
              using (CurrentTenant.Change(eventData.TenantId))
              {
                  if (eventData.Properties["SendConfirmationEmail"] == true.ToString().ToUpper() &&
                      await SettingProvider.IsTrueAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail))
                  {
                      var user = await UserManager.GetByIdAsync(eventData.Id);
                      var confirmationToken = await UserManager.GenerateEmailConfirmationTokenAsync(user);
                      await AccountEmailer.SendEmailConfirmationLinkAsync(
                          user,
                          confirmationToken,
                          eventData.Properties.GetOrDefault("AppName") ?? "MVC"
                      );
                  }
              }
          }
      }
    
    • This ensures SettingProvider (and any tenant-scoped logic like repositories, feature checks, etc.) work under the correct tenant.

    • If you need host-level settings for some reason, wrap only the required code block with Change(null).

    • Notes:

      • In-memory distributed bus handlers run in-process and may inherit the ambient tenant from the publisher scope; RabbitMQ consumers don’t, so you must explicitly set it.
      • IdentityUserCreatedEto includes TenantId; rely on it to set the tenant scope before accessing tenant-scoped services.
    1. Sources
    • https://abp.io/docs/latest/framework/infrastructure/event-bus/distributed/rabbitmq
    • https://abp.io/community/articles/daf47e17
    • https://abp.io/community/articles/ax1lgvxf

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    amansharma created

    But there is no TenantId in the IdentityUserCreatedEto.

    I have resolved this but wanted to know if there are more issues like this with the eventhandlers tenant context issues as these are hard to debug

    or is there any configuration i missed from my side, i need to know please let me know.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on November 17, 2025, 08:31
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.