c# - 租户会话在 IRealTimeNotifier 中丢失
问题描述
我们正在尝试实现用户可以通过渠道订阅通知的场景。
例如,用户可以通过电子邮件、短信、实时通知等方式订阅通知。
目前,为了实现电子邮件通知,我正在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;
}
});
});
}
}
问题在于IAbpSession
,无论我是通过属性还是构造函数注入它,在执行此通知程序时,响应已经返回并且TenantId
在此会话中是null
,因此发送的电子邮件是主机配置而不是租户配置.
同样,我需要IRealTimeNotifier
为 SMS 实现。我想我可以重用SignalRRealTimeNotifier
来自 ABP 的,但是tenantId
in 会话被设置为null
.
这是发布者被调用的地方:
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);
}
}
有人可以推荐更好的方法吗?或者指出我们在这里做错了什么。
我还没有考虑过如何处理这些特定通知器的 DI。出于测试目的,我在我的模块中给出了一个命名注入,如下所示:
IocManager.IocContainer.Register(
Component.For<IRealTimeNotifier>()
.ImplementedBy<EmailNotifier>()
.Named("Email")
.LifestyleTransient()
);
当前 ABP 版本:3.7.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:
var tenantId = userNotifications[0].Notification.TenantId;
using (AbpSession.Use(tenantId, null))
{
// ...
}
推荐阅读
- python - ElementTree XPath - 获取所有标签
- android - 在 Fragment 中创建相机预览
- python - Pandas:使用基于不同 DF 的自定义列创建 DF
- induction - Dafny 归纳引理:不能推断归纳假设的后置条件
- android - 如何检查是否创建了 Intent
- git - Git 提交 2 次
- reactjs - 将参数传递给嵌套的 React Navigation 状态
- express - express-validator isEmpty 没有错误
- javascript - 获取 WordPress API 调用 :: 如何让它实际显示在页面上
- javascript - 动画线的运动以匹配线性路径的速度