使用 UserManager 不能在 Timer 内部工作
Using UserManager not working inside Timer
在我的项目中,我试图通过 UserManager 每秒根据用户的电子邮件地址获取用户,但是当我这样做时,我收到以下错误 Cannot access a disposed object Object name: 'UserManager1
,但这是我在一个定时器()。如果我只做一次没有问题,我该如何解决?此计时器位于 SignalR 集线器正在调用的 class 内。
代码:
Timer = new System.Threading.Timer(async (e) =>
{
IEnumerable<Conversation> conversations = await _conversationsRepo.GetAllConversationsForUserEmailAsync(userMail);
List<TwilioConversation> twilioConversations = new List<TwilioConversation>();
foreach (Conversation conversation in conversations)
{
TwilioConversation twilioConversation = await _twilioService.GetConversation(conversation.TwilioConversationID);
twilioConversation.Messages = await _twilioService.GetMessagesForConversationAsync(conversation.TwilioConversationID);
twilioConversation.ParticipantNames = new List<string>();
List<TwilioParticipant> participants = await _twilioService.GetParticipantsForConversationAsync(conversation.TwilioConversationID);
foreach (TwilioParticipant participant in participants)
{
User user = await _userManager.FindByEmailAsync(participant.Email);
twilioConversation.ParticipantNames.Add(user.Name);
}
twilioConversations.Add(twilioConversation);
}
}, null, startTimeSpan, periodTimeSpan);
UserManager
以及许多其他类型是具有 scoped lifetime 的服务。这意味着它们仅在单个请求的生命周期内有效。
这也意味着长时间持有一个实例并不安全。在这个特定的例子中,UserManager
依赖于 UserStore
,它依赖于数据库连接——当请求完成时,它们肯定会被关闭。
如果你需要 运行 请求上下文之外的东西,例如在后台线程中,或者在你的情况下在某些定时执行中,那么你应该自己创建一个服务范围并检索一个您所依赖的依赖项的新实例。
为此,注入一个 IServiceScopeFactory
,然后使用它在 您的计时器代码中创建范围 。这也适用于所有其他范围内的依赖项,例如您的存储库也可能需要数据库连接:
Timer = new System.Threading.Timer(async (e) =>
{
using (var scope = serviceScopeFactory.CreateScope())
{
var conversationsRepo = scope.ServiceProvider.GetService<ConversionsRepository>();
var userManager = scope.ServiceProvider.GetService<UserManager<User>>();
// do stuff
}
}, null, startTimeSpan, periodTimeSpan);
在我的项目中,我试图通过 UserManager 每秒根据用户的电子邮件地址获取用户,但是当我这样做时,我收到以下错误 Cannot access a disposed object Object name: 'UserManager1
,但这是我在一个定时器()。如果我只做一次没有问题,我该如何解决?此计时器位于 SignalR 集线器正在调用的 class 内。
代码:
Timer = new System.Threading.Timer(async (e) =>
{
IEnumerable<Conversation> conversations = await _conversationsRepo.GetAllConversationsForUserEmailAsync(userMail);
List<TwilioConversation> twilioConversations = new List<TwilioConversation>();
foreach (Conversation conversation in conversations)
{
TwilioConversation twilioConversation = await _twilioService.GetConversation(conversation.TwilioConversationID);
twilioConversation.Messages = await _twilioService.GetMessagesForConversationAsync(conversation.TwilioConversationID);
twilioConversation.ParticipantNames = new List<string>();
List<TwilioParticipant> participants = await _twilioService.GetParticipantsForConversationAsync(conversation.TwilioConversationID);
foreach (TwilioParticipant participant in participants)
{
User user = await _userManager.FindByEmailAsync(participant.Email);
twilioConversation.ParticipantNames.Add(user.Name);
}
twilioConversations.Add(twilioConversation);
}
}, null, startTimeSpan, periodTimeSpan);
UserManager
以及许多其他类型是具有 scoped lifetime 的服务。这意味着它们仅在单个请求的生命周期内有效。
这也意味着长时间持有一个实例并不安全。在这个特定的例子中,UserManager
依赖于 UserStore
,它依赖于数据库连接——当请求完成时,它们肯定会被关闭。
如果你需要 运行 请求上下文之外的东西,例如在后台线程中,或者在你的情况下在某些定时执行中,那么你应该自己创建一个服务范围并检索一个您所依赖的依赖项的新实例。
为此,注入一个 IServiceScopeFactory
,然后使用它在 您的计时器代码中创建范围 。这也适用于所有其他范围内的依赖项,例如您的存储库也可能需要数据库连接:
Timer = new System.Threading.Timer(async (e) =>
{
using (var scope = serviceScopeFactory.CreateScope())
{
var conversationsRepo = scope.ServiceProvider.GetService<ConversionsRepository>();
var userManager = scope.ServiceProvider.GetService<UserManager<User>>();
// do stuff
}
}, null, startTimeSpan, periodTimeSpan);