SignalR-(IUserIdProvider)を使用して特定のユーザーにメッセージを送信* NEW 2.0.0 *


101

Asp.Net SignalRの最新バージョンでは、 "IUserIdProvider"インターフェイスを使用して、特定のユーザーにメッセージを送信する新しい方法が追加されました。

public interface IUserIdProvider
{
   string GetUserId(IRequest request);
}

public class MyHub : Hub
{
   public void Send(string userId, string message)
   {
      Clients.User(userId).send(message);
   }
}

私の質問は次のとおりです。メッセージの送信先をどのようにして知ることができますか?この新しい方法の説明は表面的なものです。そして、このバグを含むSignalR 2.0.0の草案はコンパイルされません。誰かがこの機能を実装しましたか?

詳細情報:http : //www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider

抱擁。


1
SignalRによる認証と承認を調べる必要があります。UserIdはIPrincipalプロバイダーの一部になります。
Gjohn

回答:


152

SignalRは、接続ごとにConnectionIdを提供します。どの接続が誰(ユーザー)に属するかを見つけるには、接続とユーザー間のマッピングを作成する必要があります。これは、アプリケーションでユーザーを識別する方法によって異なります。

SignalR 2.0では、これはIPrincipal.Identity.NameASP.NET認証中に設定されたログインユーザー識別子であるinbuiltを使用して行われます。

ただし、Identity.Nameを使用する代わりに、別の識別子を使用してユーザーとの接続をマップする必要がある場合があります。この目的のために、この新しいプロバイダーをカスタム接続で使用して、接続を持つユーザーをマッピングできます。

IUserIdProviderを使用してSignalRユーザーを接続にマッピングする例

アプリケーションがを使用しuserIdて各ユーザーを識別すると仮定しましょう。次に、特定のユーザーにメッセージを送信する必要があります。とがuserIdありますmessageが、SignalRはuserIdと接続の間のマッピングも知っている必要があります。

これを実現するには、最初に以下を実装する新しいクラスを作成する必要がありますIUserIdProvider

public class CustomUserIdProvider : IUserIdProvider
{
     public string GetUserId(IRequest request)
    {
        // your logic to fetch a user identifier goes here.

        // for example:

        var userId = MyCustomUserClass.FindUserId(request.User.Identity.Name);
        return userId.ToString();
    }
}

2番目のステップは、SignalRにCustomUserIdProviderデフォルトの実装の代わりに使用するように指示することです。これは、ハブ構成を初期化するときに、Startup.csで実行できます。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var idProvider = new CustomUserIdProvider();

        GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);          

        // Any connection or hub wire up and configuration should go here
        app.MapSignalR();
    }
}

これuserIdで、ドキュメントに記載されているように、特定のユーザーにメッセージを送信できます。

public class MyHub : Hub
{
   public void Send(string userId, string message)
   {
      Clients.User(userId).send(message);
   }
}

お役に立てれば。


こんにちは友人、遅いフィードバックをお詫びします!しかし、CustomUserIdProviderを生成するIdにアクセスしようとしましたが、「OnConnected」メソッドは同じではありません。データベース内のユーザーにリンクするにはどうすればよいですか?ありがとうございました!
イゴール2014年

7
MyCustomUserClassとは何ですか?
ダニーブリス2015

2
「MyCustomUserClass」は、FindUserIdメソッドを含むカスタムユーザークラスである可能性があります。これはほんの一例です。UserIdを返す任意のクラスに任意のメソッドを設定し、ここでそれを使用できます。
Sumant 2015

5
@Sumantに感謝します。私の問題は結局、私がWeb APIプロジェクトでベアラートークンを使用してOAuth 2を実装していたことです。その初期シグナル接続要求のヘッダー。request.User.Identity.Nameだけを使用することはできませんでした
xinunix

1
@Sumant私はすでにそれを解決しました。問題は、app.MapSignalR();認証の前にglobal.asax を配置することでした。
Mr. Robot

38

これが始まりです。提案/改善にオープンです。

サーバ

public class ChatHub : Hub
{
    public void SendChatMessage(string who, string message)
    {
        string name = Context.User.Identity.Name;
        Clients.Group(name).addChatMessage(name, message);
        Clients.Group("2@2.com").addChatMessage(name, message);
    }

    public override Task OnConnected()
    {
        string name = Context.User.Identity.Name;
        Groups.Add(Context.ConnectionId, name);

        return base.OnConnected();
    }
}

JavaScript

(注意方法addChatMessagesendChatMessage、上記サーバコード内のメソッドです)

    $(function () {
    // Declare a proxy to reference the hub.
    var chat = $.connection.chatHub;
    // Create a function that the hub can call to broadcast messages.
    chat.client.addChatMessage = function (who, message) {
        // Html encode display name and message.
        var encodedName = $('<div />').text(who).html();
        var encodedMsg = $('<div />').text(message).html();
        // Add the message to the page.
        $('#chat').append('<li><strong>' + encodedName
            + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
    };

    // Start the connection.
    $.connection.hub.start().done(function () {
        $('#sendmessage').click(function () {
            // Call the Send method on the hub.
            chat.server.sendChatMessage($('#displayname').val(), $('#message').val());
            // Clear text box and reset focus for next comment.
            $('#message').val('').focus();
        });
    });
});

テスト中 ここに画像の説明を入力してください


こんにちは友人、遅いフィードバックをお詫びします!しかし、どうすればCONNECTIONIDの損失を防ぐことができますか?ありがとうございました。
イゴール2014年

5
@lgaoわかりません。
マフィンマン

この行が必要な理由--- Clients.Group( "2@2.com")。addChatMessage(name、message); ??
Thomas

@Thomasおそらく、デモのために含めました。これはハードコーディングされているため、特定のグループにブロードキャストする別の方法が必要です。
マフィンマン

この簡単な解決策は、特定のログインユーザーにメッセージを送信するという私の問題を解決しました。そのシンプルで高速、そして理解しやすいです。できれば、この回答に何度か賛成します。
Rafael AMS

5

これは、(プロバイダーを使用せずに)特定のユーザーをターゲットにするためにSignarRを使用する方法です。

 private static ConcurrentDictionary<string, string> clients = new ConcurrentDictionary<string, string>();

 public string Login(string username)
 {
     clients.TryAdd(Context.ConnectionId, username);            
     return username;
 }

// The variable 'contextIdClient' is equal to Context.ConnectionId of the user, 
// once logged in. You have to store that 'id' inside a dictionaty for example.  
Clients.Client(contextIdClient).send("Hello!");

2
これをどのように使用しているかはわかりcontextIdClientません:(
Neo

2

機能については、SignalRテストご覧ください。

テスト「SendToUser」は、通常のowin認証ライブラリを使用して渡されたユーザーIDを自動的に取得します。

シナリオは、複数のデバイス/ブラウザーから接続しているユーザーがいて、すべてのアクティブな接続にメッセージをプッシュすることです。


ありがとう!しかし、プロジェクトバージョン2.0は、ここではSignalRをコンパイルしていません。(残念ながら、私はそれにアクセスすることはできません。。
イゴール

0

古いスレッドですが、サンプルでこれに遭遇しました:

services.AddSignalR()
            .AddAzureSignalR(options =>
        {
            options.ClaimsProvider = context => new[]
            {
                new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
            };
        });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.