web-dev-qa-db-ja.com

ユーザーへのSignalR接続のマッピング

Facebookのような、リアルタイム通知をユーザーに送信できるWebアプリケーションを考えてみましょう。

asp.net SignalR を使用して、ユーザーが切断または再接続した場合でも、どのユーザーにどの接続IDが属しているかを追跡する最良の方法は何ですか?

28
Daniel Hursan

次のブログ投稿をご覧ください。

ASP.NET SignalR接続の実際のアプリケーションユーザーへのマッピング

簡単に言うと、OnConnectedメソッドでユーザーに接続IDを追加し、OnDisconnectedメソッドでその接続を削除します。アプリケーションユーザーは複数の接続を持つことができることに注意してください。したがって、ユーザーと接続IDの間には1対多の関係が必要です。上記のリンク先の投稿では、サンプルを使用して詳細に説明しています。

27
tugberk

私は内部アプリのためにこれを行いました。私が行った方法は、ユーザーが接続すると、サーバーにユーザーに登録を依頼するというものです。このようにして、ユーザーが接続され、そのsignalR connnectionIDだけでなく、他の情報(ユーザー名など)も教えてくれることがわかります。

彼らが再接続するとき、私は彼らにもう一度それをするように頼みます。

再接続しても、SignalRはクライアントごとに同じconnectionIDを維持します。再接続は初期接続と同じではありません。新しい接続は新しいクライアントを示しますが、再接続は同じクライアント上で行われます。

私のアプリでは、どのユーザーとどのconnectionIDが何をしているのかを追跡する別のスレッドセーフディクショナリを維持しました。このようにして、「ああ、ユーザーABCにメッセージを送信」と言って、その接続IDを調べることができます。次に、そのconnectionIDのsignalRでハブのクライアントオブジェクトを操作します。このようにすると、複数の接続で同じ「ユーザー」を持つこともできます。ユーザー "abc"が2つのブラウザタブで開いているとします。厳密にconnectionIDで行った場合、技術的には2人の異なるユーザーになります。ただし、ローカルコレクショングループのユーザーと接続の種類を維持することにより、同じユーザーに対して複数の接続を確立できます。

この方法でこれを行う場合は、サイトが再起動したときに発生する処理をサイトが処理し、すべての接続情報が失われるようにする必要があります。私にとって、誰かが再接続するとき、私は彼らに再び彼ら自身を再確認するように頼みます。これにより、サーバーが心配なくオンラインになったときに、ローカル辞書を再構築できます。すべてのクライアントに情報を送信するように要求しているため、オーバーヘッドは大きくなりますが、ユーザーのケースによっては、負荷を処理するために、ずらしたり、まとめたり、その他の方法で分散したりできます。

ただし、一般に、ローカル情報を取得するか(ユーザーに提供を要求するかどうか)、またはhttpコンテキストセッション情報を取得する場合は、自分で追跡する必要があります。

6
devshorts

まあ、私は別のアプローチを使用して、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;
    }

編集:

ハブコードには、ユーザーの子オブジェクトの読み込みに問題があります。 asp.netテンプレートでも使用されるこのコードはより適切に機能し、ApplicationDBContextは必要ありません。

    private ApplicationUserManager _userManager
    {
        get
        {
            return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
    }


    var user = _userManager.FindByName<ApplicationUser, string>(userName);
3
Ronen Festinger

ASP.NETのSignalRチュートリアルセクションに関する非常に優れた記事があります。以下の紹介段落を含めました。

SignalRユーザーの接続へのマッピング

ハブに接続する各クライアントは、一意の接続IDを渡します。この値は、ハブコンテキストのContext.ConnectionIdプロパティで取得できます。アプリケーションでユーザーを接続IDにマップし、そのマッピングを維持する必要がある場合は、次のいずれかを使用できます。

  • ユーザーIDプロバイダー(SignalR 2)
  • 辞書などのメモリ内ストレージ
  • 各ユーザーのSignalRグループ

データベーステーブルやAzureテーブルストレージなどの永続的な外部ストレージこれらの各実装について、このトピックで説明します。 Hubクラスの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);
    }
}
0
Simon_Weaver