且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何安全地向特定用户发送消息

更新时间:2023-01-15 19:24:18

更新日期

注意:我正在一个电子商务网站上,即使用户处于脱机状态,用户也需要能够接收消息(消息将存储在DB中,并且一旦联机就可以阅读).

Note: I am working on an e-commerce website where users need to be able to receive messages even if they are offline (the messages would be stored in DB and they can read once the are online).

执行以下操作,以安全的方式使用随机生成的connectionId发送消息:

首先添加以下类来跟踪用户的connectionId,以了解用户是在线还是离线

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

Configure the ChatHub as follows

要使ChatHub受保护,请在ChatHub类上添加[Authorize]属性.

To make the ChatHub secured add [Authorize] attribute on the ChatHub class.

[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; }
}

然后在消息控制器中:

这只是示例代码.您可以根据自己的实际需求自定义代码.

This is just an example code. You can customize the code according to your exact need.

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

现在的问题是,如果接收方离线时是否发送了消息,该怎么办?

Now question is what if the message was sent whenever the receiver was offline?

好吧!在这种情况下,您可以通过两种方式处理推送通知!接收者在线后立即调用ajax方法或SignalR Hub方法来绑定通知.另一种方法是将局部视图用于布局页面中的通知区域.我个人更喜欢将局部视图用于通知区域.

Okay! In this case you can handle the push notification in two ways! calling a ajax method or SignalR Hub method as soon as the receiver is online to bind the notifications. Another method is using partial view for notification area in layout page. I personally prefer using partial view for notification area.

希望这对您有帮助!