Обновлено
Примечание. Я работаю на веб-сайте электронной коммерции, где пользователи должны иметь возможность получать сообщения, даже если они находятся в автономном режиме (сообщения будут храниться в БД, и их можно будет прочитать, как только они появятся в сети).
Выполните следующие действия для отправки сообщения с использованием случайно сгенерированного идентификатора соединения в защищенном виде:
Сначала добавьте следующие классы для отслеживания идентификаторов соединений пользователя, чтобы понять, подключен ли пользователь к сети или нет
public static class ChatHubUserHandler
{
public static ConcurrentDictionary<string, ChatHubConnectionViewModel> ConnectedIds =
new ConcurrentDictionary<string, ChatHubConnectionViewModel>(StringComparer.InvariantCultureIgnoreCase);
}
public class ChatHubConnectionViewModel
{
public string UserName { get; set; }
public HashSet<string> UserConnectionIds { get; set; }
}
Настройте ChatHub
следующим образом
Чтобы сделать защищенный атрибут ChatHub
, добавьте [Authorize]
в класс ChatHub
.
[Authorize]
public class ChatHub : Hub
{
private string UserName => Context.User.Identity.Name;
private string ConnectionId => Context.ConnectionId;
// Whenever a user will be online randomly generated connectionId for
// him be stored here.Here I am storing this in Memory, if you want you
// can store it on database too.
public override Task OnConnected()
{
var user = ChatHubUserHandler.ConnectedIds.GetOrAdd(UserName, _ => new ChatHubConnectionViewModel
{
UserName = UserName,
UserConnectionIds = new HashSet<string>()
});
lock (user.UserConnectionIds)
{
user.UserConnectionIds.Add(ConnectionId);
}
return base.OnConnected();
}
// Whenever a user will be offline his connectionId id will be
// removed from the collection of loggedIn users.
public override Task OnDisconnected(bool stopCalled)
{
ChatHubConnectionViewModel user;
ChatHubUserHandler.ConnectedIds.TryGetValue(UserName, out user);
if (user != null)
{
lock (user.UserConnectionIds)
{
user.UserConnectionIds.RemoveWhere(cid => cid.Equals(ConnectionId));
if (!user.UserConnectionIds.Any())
{
ChatHubUserHandler.ConnectedIds.TryRemove(UserName, out user);
}
}
}
return base.OnDisconnected(stopCalled);
}
}
Теперь используйте следующий класс модели для сохранения сообщения в базе данных. Вы также можете настроить класс сообщения в соответствии с вашими потребностями.
public class Message
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long MessageId { get; set; }
[ForeignKey("Sender")]
public string SenderId { get; set; }
[ForeignKey("Receiver")]
public string ReceiverId { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string MessageBody { get; set; }
public DateTime MessageSentAt { get; set; }
public bool IsRead { get; set; }
public User Sender { get; set; }
public User Receiver { get; set; }
}
Затем в контроллере сообщений:
Это просто пример кода. Вы можете настроить код в соответствии с вашими потребностями.
[HttpPost]
public async Task<ActionResult> SendMessage(string messageBody, string receiverAspNetUserId)
{
string loggedInUserId = User.Identity.GetUserId();
Message message = new Message()
{
SenderId = loggedInUserId,
ReceiverId = receiverAspNetUserId,
MessageBody = messageBody,
MessageSentAt = DateTime.UtcNow
};
_dbContext.Messages.Add(message);
_dbContext.SaveChangesAsync();
// Check here if the receiver is currently logged in. If logged in,
// send push notification. Send your desired content as parameter
// to sendPushNotification method.
if(ChatHubUserHandler.ConnectedUsers.TryGetValue(receiverAspNetUserId, out ChatHubConnectionViewModel connectedUser))
{
List<string> userConnectionIds = connectedUser.UserConnectionIds.ToList();
if (userConnectionIds.Count > 0)
{
var chatHubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
chatHubContext.Clients.Clients(userConnectionIds).sendPushNotification();
}
}
return Json(true);
}
Теперь вопрос в том, что если сообщение было отправлено, когда получатель был в автономном режиме?
Хорошо! В этом случае вы можете обработать push-уведомление двумя способами! вызов метода ajax или метода SignalR Hub, как только получатель подключится к сети для привязки уведомлений. Другой метод - частичное представление области уведомлений на странице макета. Лично я предпочитаю использовать частичное представление для области уведомлений.
Надеюсь, это поможет вам!