Сопоставление соединений SignalR с пользователями
Рассмотрим веб-приложение, подобное facebook, которое может отправлять пользователям в реальном времени уведомления.
Каков наилучший способ использования asp.net SignalR, чтобы отслеживать, какие идентификаторы подключений принадлежат тому пользователю, даже если пользователь отключается или повторно подключается позже
Ответы
Ответ 1
Обратите внимание на следующее сообщение в блоге:
Отображение соединений ASP.NET SignalR с реальными пользователями приложений
Вкратце, вы добавляете идентификаторы подключения к пользователю по методу OnConnected
и удаляете это соединение по методу OnDisconnected
. Имейте в виду, что пользователь приложения может иметь несколько соединений. Таким образом, между вашим пользователем и идентификаторами подключения должно быть отношение один-много. Вышеупомянутая ссылка объясняет это подробно с образцом.
Ответ 2
Я сделал это для внутреннего приложения. То, как я это делал, заключается в том, что когда пользователь подключается, у меня есть сервер, который просит пользователя зарегистрироваться. Таким образом, я знаю, что подключен не только пользователь и их идентификатор соединения signalR, но также могут сообщить мне любую другую информацию (например, имя пользователя или что-то еще).
Когда они снова подключатся, я прошу их сделать это снова.
SignalR будет поддерживать один и тот же идентификатор соединения на клиент, даже если они снова подключится, что приятно. Повторное соединение не совпадает с исходным соединением. Новые подключения указывают на новый клиент, но переподключение происходит на одном клиенте.
В моем приложении я поддерживал отдельный словарь потокобезопасности, который я отслеживал, какой пользователь и какой connectionID что делает. Таким образом, я могу сказать "о, отправить сообщение пользователю ABC" и посмотреть их идентификатор соединения. Затем действуйте на объект клиентов-концентратора в signalR для этого идентификатора соединения. Если вы сделаете это так, вы можете даже иметь одного и того же "пользователя" в mutliple соединениях. Представьте, что пользователь "abc" открыт в двух вкладках браузера. Если вы строго придерживаетесь connectionID, они будут технически двумя разными пользователями. Но, поддерживая некоторые локальные пользователи группировки коллекций и соединений, вы можете теперь иметь несколько подключений для одного и того же пользователя.
Я должен упомянуть, что если вы сделаете это так, вы должны убедиться, что ваш сайт обрабатывает то, что происходит, когда он перезагружается и теряет всю информацию о подключении. Для меня, когда кто-то снова подключается, я прошу их снова переименовать себя. Таким образом, я могу перестроить свой локальный словарь, когда сервер приходит в интернет, не беспокоясь. У этого есть больше накладных расходов, потому что теперь вы просите всех своих клиентов отправлять вам информацию, но в зависимости от вашего случая пользователя это может быть пошатнуто или сгруппировано или иным образом распространено, чтобы помочь вам справиться с нагрузкой.
В общем, однако вы получаете локальную информацию (будь то, спрашивая у пользователя, чтобы ее предоставить), или через информацию о сеансе http-контекста, вам нужно отслеживать ее самостоятельно.
Ответ 3
Ну, я использовал другой подход, я расширил класс ApplicationUser следующим образом:
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
//public int ApplicationUserId { get; set; }
//public string Name { get; set; }
//public string Address { get; set; }
//public string City { get; set; }
//public string State { get; set; }
//public string Zip { get; set; }
[Required]
public string Email { get; set; }
[Required]
public override string UserName { get; set; }
[NotMapped]
public string ConnectionId { get; set; }
[NotMapped]
public string ChattingUserConnectionId { get; set; }
//public string HomeTown { get; set; }
//public DateTime? BirthDate { get; set; }
}
И в моем хабе я делаю что-то вроде этого:
public class ChatHub : Hub
{
#region Data Members
private static ApplicationDbContext applicationDbContext = new ApplicationDbContext();
private static UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
private static List<ApplicationUser> connectedUsers = new List<ApplicationUser>();
И когда пользователь подключается к чату, я получаю его объект ApplicationUser своим именем пользователя и добавляю его в список connectedUsers. Когда он отключается, я удаляю его.
Я столкнулся с некоторыми случайными исключениями с состояниями EF и такими, которые заставляли меня создавать ApplicationDbContext и UserManager каждый раз, когда к нему обращаются, вместо того, чтобы устанавливать его в статическом объекте:
private ApplicationUser GetCurrentUser()
{
ApplicationDbContext applicationDbContext = new ApplicationDbContext();
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
var userName = Context.User.Identity.GetUserName();
var user = userManager.FindByName<ApplicationUser>(userName);
return user;
}
Edit:
В коде концентратора возникают некоторые проблемы с загрузкой дочерних объектов пользователя. Этот код, который также используется в шаблоне asp.net, будет работать лучше, ApplicationDBContext не нужен:
private ApplicationUserManager _userManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
}
var user = _userManager.FindByName<ApplicationUser, string>(userName);
Ответ 4
Там очень хорошая статья об учебном разделе ASP.NET SignalR.
Я включил вводный параграф ниже.
Каждый клиент, подключающийся к концентратору, передает уникальный идентификатор соединения. Ты можешь получить это значение в свойстве Context.ConnectionId концентратора контекст. Если вашему приложению необходимо сопоставить пользователя с идентификатором соединения и сохраняйте это отображение, вы можете использовать одно из следующих значений:
- Поставщик идентификатора пользователя (SignalR 2)
- Хранилище в памяти, такое как словарь
- Группа SignalR для каждого пользователя
Постоянное внешнее хранилище, такое как таблица базы данных или таблица Azure хранилище. Каждая из этих реализаций показана в этом разделе. Ты используешь методы OnConnected, OnDisconnected и OnReconnected концентратора класс для отслеживания состояния подключения пользователя.
Поставщик UserID
Если вы используете стандартный поставщик членства в ASP.NET(IPrincipal.Identity.Name
), вы можете просто сделать следующее для доступа к клиенту на основе учетной записи пользователя. Если у вас есть собственная пользовательская система, вы можете создать своего собственного провайдера.
public class MyHub : Hub
{
public void Send(string userId, string message)
{
Clients.User(userId).send(message);
}
}