更新日
注: 私は、ユーザーがオフラインであってもメッセージを受信できる必要がある e コマース Web サイトで作業しています (メッセージは DB に保存され、オンラインになると読み取ることができます)。
安全な方法でランダムに生成された connectionId を使用してメッセージを送信するには、次の手順を実行します。
最初に次のクラスを追加して、ユーザーの connectionIds を追跡し、ユーザーがオンラインかオフラインかを把握します。
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);
}
ここで問題は、受信者がオフラインのときにメッセージが送信された場合はどうなるかということです。
わかった!この場合、プッシュ通知を 2 つの方法で処理できます。受信者がオンラインになるとすぐに ajax メソッドまたは SignalR Hub メソッドを呼び出して、通知をバインドします。別の方法は、レイアウト ページの通知領域の部分ビューを使用することです。個人的には、通知領域に部分ビューを使用することを好みます。
これがあなたを助けることを願っています!