Tenant session is lost in IRealTimeNotifier

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Tenant session is lost in IRealTimeNotifier



We are trying to achieve a scenario where user can subscribe to notifications via channels.



For example, user can subscribe to notifications via Email, SMS, Real Time Notifications, etc.



For now, in order to achieve email notifications, I am implementing the IRealTimeNotifier in this way:


IRealTimeNotifier


public class EmailNotifier : IRealTimeNotifier, ITransientDependency

private readonly IEmailSender _emailSender;
private readonly ISettingManager _settingManager;

public IAbpSession AbpSession get; set;

public EmailNotifier(IEmailSender emailSender, ISettingManager settingManager, IAbpSession abpSession)

this._emailSender = emailSender;
this._settingManager = settingManager;
this.AbpSession = NullAbpSession.Instance;


public async Task SendNotificationsAsync(UserNotification userNotifications)

List<Task> sendEmails = new List<Task>();
string fromAddress = this._settingManager.GetSettingValueForTenant(EmailSettingNames.Smtp.UserName, Convert.ToInt32(this.AbpSession.TenantId));

foreach (UserNotification notification in userNotifications)

notification.Notification.Data.Properties.TryGetValue("toAddresses", out object toAddresses);
notification.Notification.Data.Properties.TryGetValue("subject", out object sub);
notification.Notification.Data.Properties.TryGetValue("body", out object content);
notification.Notification.Data.Properties.TryGetValue("toAddresses", out object toAddresses);

List<string> toEmails = toAddresses as List<string> ;
string subject = Convert.ToString(sub);
string body = Convert.ToString(content);
toEmails.ForEach(to =>

sendEmails.Add(this._emailSender.SendAsync(fromAddress, to, subject, body));
);


await Task.Run(() =>

sendEmails.ForEach(async task =>

try

await task.ConfigureAwait(false);

catch (Exception)

// TODO #1: Add email to background job to be sent later.
// TODO #2: Add circuit breaker to email sending mechanism
/*
Email sending is failing because of two possible reasons.
1. Email addresses are wrong.
2. SMTP server is down.
3. Break the circuit while the SMTP server is down.
*/

// TODO #3 (Optional): Notify tenant admin about failure.
// TODO #4: Remove throw statement for graceful degradation.
throw;

);
);




The problem is with the IAbpSession, whether I inject it via property or constructor, at the time of execution of this notifier, the response has already been returned and the TenantId in this session is null, so the email is being sent with host configurations and not tenant configuration.


IAbpSession


TenantId


null



Similarly, I need to implement IRealTimeNotifier for SMS. I think I can reuse the SignalRRealTimeNotifier from ABP, but the tenantId in session is being set to null.


IRealTimeNotifier


SignalRRealTimeNotifier


tenantId


null



This is where the publisher is being called:


public class EventUserEmailer : IEventHandler<EntityCreatedEventData<Event>>

public ILogger Logger get; set;

private readonly IEventManager _eventManager;
private readonly UserManager _userManager;
private readonly IAbpSession _abpSession;
private readonly INotificationPublisher _notiticationPublisher;

public EventUserEmailer(
UserManager userManager,
IEventManager eventManager,
IAbpSession abpSession,
INotificationPublisher notiticationPublisher)

_userManager = userManager;
_eventManager = eventManager;
_notiticationPublisher = notiticationPublisher;
_abpSession = abpSession;
Logger = NullLogger.Instance;


[UnitOfWork]
public virtual void HandleEvent(EntityCreatedEventData<Event> eventData)

// TODO: Send email to all tenant users as a notification

var users = _userManager
.Users
.Where(u => u.TenantId == eventData.Entity.TenantId)
.ToList();

// Send notification to all subscribed uses of tenant
_notiticationPublisher.Publish(AppNotificationNames.EventCreated);




Can anybody recommend a better way? Or point anything out that we are doing wrong here.



I have not thought about how to handle DI of these particular notifiers yet. For testing purposes, I have given a named injection in my module like this:


IocManager.IocContainer.Register(
Component.For<IRealTimeNotifier>()
.ImplementedBy<EmailNotifier>()
.Named("Email")
.LifestyleTransient()
);



Current ABP version: 3.7.1



This is the information I have until now. If anything is needed, you can ask in comments.




1 Answer
1


// Send notification to all subscribed uses of tenant
_notificationPublisher.Publish(AppNotificationNames.EventCreated);



If you publish notifications like this, ABP's default implementation enqueues a background job.



There is no session in a background job.



You can get the tenantId like this:


tenantId


var tenantId = userNotifications[0].Notification.TenantId;

using (AbpSession.Use(tenantId, null))

// ...





Sorry for the delayed response, Yes it worked! Thanks a ton.
– Saurabh Pati
Aug 13 at 10:12






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard