Использование UserManager не работает внутри таймера - PullRequest
0 голосов
/ 25 марта 2020

В моем проекте я пытаюсь получить пользователя на основе его адреса электронной почты каждую секунду с помощью UserManager, но когда я делаю это, я получаю следующую ошибку Cannot access a disposed object Object name: 'UserManager1, но это когда я делаю это внутри Timer () , Если я просто сделаю это один раз, когда нет проблем, как я могу это исправить? Этот таймер находится внутри класса, который вызывается концентратором SignalR.

Код:

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);

1 Ответ

1 голос
/ 25 марта 2020

UserManager наряду со многими другими типами - это сервис, который имеет срок действия в области действия . Это означает, что они действительны только в течение времени жизни одного запроса.

Это также означает, что удерживать экземпляр дольше не безопасно. В этом конкретном примере UserManager зависит от UserStore, который зависит от соединения с базой данных - и они обязательно будут закрыты после завершения запроса.

Если вам нужно запустить что-то за пределами контекст запроса, например, в фоновом потоке или, в вашем случае, при каком-то временном выполнении, тогда вы должны сами создать область обслуживания и получить бесплатный экземпляр sh зависимости, на которую вы полагаетесь.

Для этого введите 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);
...