Base solution for your next web application
Open Closed

TenantId null after using NotificationPublisher in EventBus #1981


User avatar
0
explothunder created

Hi there! I'm trying to understand a strange behaviour related to the EventBus.

I have an event handler class named TimesheetNotifier, which purpose is to send both notification and email to subscribed users. The handler method is listed below:

[UnitOfWork]
public void HandleEvent(MonthAccountingEventData eventData)
{
	IList<User> usersByNotificationPermission = (UserManager.GetUsersByPermission(AppPermissions.Notifications_Timesheet_Accounting)).ToList();

	if (usersByNotificationPermission.Count > 0) {

		// Prepare Email content
		string emailSubject = L("Emails_Timesheet_Accounting_Subject");
		var flow = _timesheetManager.GetTimeflowById(eventData.TimeFlowId);
		string _date = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(flow.Month) + " " + flow.Year;
		emailSubject = emailSubject.Replace(Placeholder.Date, _date);

		string emailTemplate = _emailTemplateProvider.GetDefaultTemplateFilled(L("Emails_Timesheet_Accounting_Title"),
																			   L("Emails_Timesheet_Accounting_Subtitle"),
																			   L("Emails_Timesheet_Accounting_Message"),
																			   AbpSession.TenantId);

		emailTemplate = FillPlaceholders(emailTemplate, base.PlaceHolderReplacement);

		// Send Notification and Mail
		foreach(var user in usersByNotificationPermission)
		{
			NotificationData notificationData = new NotificationData(user.ToUserIdentifier(),
																	user.UserName,
																	user.IsActive,
																	L("Notifications_Timesheet_Accounting_Message"),
																	AppNotificationNames.TimesheetNotification);

			AsyncHelper.RunSync(() => SendSafeNotificationAsync(notificationData));

			EmailData emailData = new EmailData(user.ToUserIdentifier(),
												user.UserName,
												user.IsActive,
												user.EmailAddress, 
												emailSubject, 
												emailTemplate.Replace(Placeholder.User_Name, user.Name), 
												AppNotificationNames.TimesheetNotification);

			AsyncHelper.RunSync(() => SendSafeEmailAsync(emailData));
		}

		AsyncHelper.RunSync(() => base.SendLogToDev("Timesheet"));
	}
}

This class derives from another, NotifierBase, which implements SendSafeEmailAsync, SendSafeNotificationAsync, SendLogToDev methods.

The problem is the following one: after the notification send (not the email one), trying to execute any linq query by the UserManager (e.g. a simple UserManager.Users.ToList()), it returns only the admin (the only record with tenantid = null).

The implementation of SendSafeNotificationAsync checks if the user is subscribed to the notification and uses the NotificationPublisher PublishAsync method to deliver the notification to the user; analyzing the query by SQL Server Profiler I noticed that in the query conditions the tenantId is requested to be null instead of the current tenant. But the strange thing is that AbpSession continues to have the current tenant set correctly.

I list below a test I've done:

var tenantid_before = AbpSession.TenantId;
var tmp_before = _userManager.Users.ToList();

await _notificationPublisher.PublishAsync(
	appNotificationName,
	new MessageNotificationData(message),
	severity: severity,
	userIds: new[] { userIdentifier }
	);

var tmp_after = _userManager.Users.ToList();
var tenantid_after = AbpSession.TenantId;

in this example:

  • tenantid_before equals to 1
  • tmp_before counts 145 elements

-tenantid_after equals to 1 -tmp_after counts 1 element

Also after the Trigger method in the TimesheetAppService the UserManager continues to provide only the rows with tenantId = null

I solved setting the tenantId in the UoW before sending the notification using UnitOfWorkManager.Current.SetTenantId(data.RecipientIdentifier.TenantId) method, but in my opinion it isn't a good practice.. What do you think about?

Thanks in advance, Alex


No answer yet!