2015-01-02 4 views
1

В моем приложении MVC пользователь I SignalR для связи между пользователями. В принципе, клиент вызывает метод на концентраторе, который вызывает метод в репозитории, который затем сохраняет сообщение в базе данных, а концентратор уведомляет другого клиента о новом сообщении.Время жизни класса UserManager SignalR и ASP.NET

я использовал метод GetOwinContext() во время этих звонков от клиента, чтобы получить текущий экземпляр UserManager и ApplicationDbContext, используя методы расширения GetUserManager<UserManager>() и Get<ApplicationDbcontex>() соответственно. Тем не менее, я заметил, что вызовы из одного и того же соединения используют один и тот же контекст, что, очевидно, не очень хорошо. Я пошел вперед и изменил мое хранилище так, как это сейчас:

public XyzRepository() //constructor 
    { 
     db = ApplicationDbContext.Create(); //static method that generates a new instance 
    } 
    private ApplicatonDbContext db { get; set; }  
    private UserManager UserManager 
    { 
     get 
     { 
      return new UserManager(new UserStore<ApplicationUser>(db)); //returns a new UserManager using the context that is used by this instance of the repository 
     } 
    } 

Поскольку я ссылаться на ApplicationUser объектов с помощью UserManager (с использованием FindByIdAsync() и т.д., в зависимости от конструкции), крайне важно использовать контекст В настоящее время я работаю для UserStore текущего экземпляра UserManager. Репозиторий создается один раз за запрос, который, по-видимому, применяется к каждому вызову SignalR, как предполагалось. Пока я не испытывал проблем с этим дизайном, после прочтения этой проблемы (в статье this), в частности, этой строки:

«В текущем подходе, если в запросе есть два экземпляра UserManager, работать над тем же пользователем, они будут работать с двумя различными экземплярами пользовательского объекта», я решил обратиться к сообществу:.

Вопрос:, что является предпочтительным способом использовать UserManager класс ASP.NET удостоверений с SignalR, если это императив, что я использую тот же экземпляр DbContext для методов моего хранилища t hat UserManagerUserStore использует?

ответ

2

Я думаю, что предпочтительным способом является использование контейнеров Inversion of Control и конструктор-инъекций с какой-то видимой областью видимости. Вот еще один вопрос, который вы можете захотеть взглянуть на:

Using Simple Injector with SignalR

Предпочтительно, чтобы ваш DbContext экземпляра жить так долго, как текущий веб-запрос. В контейнерах IoC есть возможности, позволяющие регистрировать DbContext экземпляров с каждым сроком службы веб-запроса, но вам нужно настроить контейнер IoC, чтобы он мог управлять построением классов Hub для достижения этого. Некоторые контейнеры IoC (например, SimpleInjector) также автоматически удаляют DbContext в конце веб-запроса для вас, поэтому вам не нужно ничего обертывать в блоке using.

Что касается UserManager, XyzRepository и т. Д., Я думаю, что они также могут иметь срок службы для каждого веб-сайта или даже временные периоды жизни. В конце концов, я не понимаю, почему вы не смогли бы добиться чего-то вроде этого:

public class MyXyzHub : Hub 
{ 
    private readonly UserManager<ApplicationUser> _userManager; 
    private readonly MessageRepository _messageRepository; 

    public MyXyzHub(UserManager<ApplicationUser> userManager, 
     MessageRepository messageRepository) 
    { 
     _userManager = userManager; 
     _messageRepository= messageRepository; 
    } 

    public void sendMessage(string message) 
    { 
     var user = _userManager.FindByIdAsync(... 
     _messageRepository.CreateAndSave(new Message 
     { 
      Content = message, UserId = user.Id 
     }); 
     Clients.All.receiveMessage(message, user.Name); 
    } 
} 

Если вы телеграфировать ваш контейнер IoC правильный путь, то каждый раз, когда концентратор построен, он должен повторно использовать тот же ApplicationDbContext экземпляр для текущего веб-запроса. Также с вашим текущим кодом, похоже, что XyzRepository никогда не удаляет ваш ApplicationDbContext, что является еще одной проблемой, с которой может помочь вам контейнер IoC.

+0

Спасибо, я сделал это.Однако Niject ведет себя несколько неожиданно. Используя 'InRequestScope()', после вызова первого метода на концентраторе он создает новые экземпляры репозитория, DbContext и UserManager, как предполагалось. Однако вызов дополнительных методов не приводит к появлению новых экземпляров; тот же контекст используется, что, конечно, очень неудачно. Но так как это несвязанная проблема, и ваш ответ был совершенным, я принимаю его. – Riwen

+1

@Shinzon, пока все другие методы вызываются с тем же экземпляром DbContext во время одного и того же веб-запроса, я не согласен с тем, что это неудачно. Это намеренно и желательно ИМО. Я считаю, что InRequestScope хранит DbContext в HttpContext.Current.Items и удаляет его во время Application_EndRequest. Разве это не так? С таким видом вашего DbContext не будет жить слишком долго, но он будет жить достаточно долго, чтобы сделать все необходимое для одного веб-запроса. – danludwig

+0

Проблема заключается в том, что Application_EndRequest не запускается при вызове метода SignalR с клиента, поэтому DbContext не удаляется. – Riwen

Смежные вопросы