SignalR - Mengirim pesan ke pengguna tertentu menggunakan (IUserIdProvider) * BARU 2.0.0 *


101

Dalam versi terbaru Asp.Net SignalR, telah ditambahkan cara baru untuk mengirim pesan ke pengguna tertentu, menggunakan antarmuka "IUserIdProvider".

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

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

Pertanyaan saya adalah: Bagaimana saya tahu kepada siapa saya mengirim pesan saya? Penjelasan tentang metode baru ini sangat dangkal. Dan draft Pernyataan SignalR 2.0.0 dengan bug ini dan tidak dapat dikompilasi. Adakah yang sudah menerapkan fitur ini?

Info Lebih Lanjut: http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider

Pelukan.


1
Anda perlu memeriksa Otentikasi dan Otorisasi dengan SignalR. UserId akan menjadi bagian dari penyedia IPrincipal.
Gjohn

Jawaban:


153

SignalR menyediakan ConnectionId untuk setiap koneksi. Untuk mengetahui koneksi mana yang dimiliki siapa (pengguna), kita perlu membuat pemetaan antara koneksi dan pengguna. Ini tergantung pada bagaimana Anda mengidentifikasi pengguna dalam aplikasi Anda.

Di SignalR 2.0, ini dilakukan dengan menggunakan inbuilt IPrincipal.Identity.Name, yang merupakan pengenal pengguna yang masuk sebagaimana ditetapkan selama otentikasi ASP.NET.

Namun, Anda mungkin perlu memetakan koneksi dengan pengguna menggunakan pengenal yang berbeda daripada menggunakan Identity.Name. Untuk tujuan ini, penyedia baru ini dapat digunakan dengan implementasi kustom Anda untuk memetakan pengguna dengan koneksi.

Contoh Pemetaan Pengguna SignalR ke Koneksi menggunakan IUserIdProvider

Anggaplah aplikasi kita menggunakan a userIduntuk mengidentifikasi setiap pengguna. Sekarang, kita perlu mengirim pesan ke pengguna tertentu. Kami memiliki userIddan message, tetapi SignalR juga harus mengetahui pemetaan antara userId kami dan koneksi.

Untuk mencapai ini, pertama kita perlu membuat kelas baru yang mengimplementasikan 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();
    }
}

Langkah kedua adalah memberi tahu SignalR untuk menggunakan kami CustomUserIdProvideralih - alih implementasi default. Ini dapat dilakukan di Startup.cs saat menginisialisasi konfigurasi hub:

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

Sekarang, Anda dapat mengirim pesan ke pengguna tertentu menggunakan miliknya userIdseperti yang disebutkan dalam dokumentasi, seperti:

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

Semoga ini membantu.


Hai teman, maaf atas tanggapan yang terlambat! Tetapi saya mencoba mengakses Id yang menghasilkan CustomUserIdProvider tetapi metode "OnConnected" tidak sama. Bagaimana cara saya menautkan ke Pengguna di database? Terima kasih!
Igor

7
Apa itu MyCustomUserClass?
Danny Bullis

2
"MyCustomUserClass" bisa menjadi kelas pengguna kustom Anda yang berisi metode FindUserId. Ini hanya sebagai contoh. Anda dapat memiliki metode apa pun di kelas mana pun yang mengembalikan UserId Anda dan menggunakannya di sini.
Sumant

5
Terima kasih @Sumant, masalah saya akhirnya adalah karena saya berada dalam proyek API Web tempat saya menerapkan OAuth 2 dengan token pembawa, saya harus menerapkan logika untuk meneruskan token pembawa pada string kueri karena tidak dapat ditarik dari header pada permintaan koneksi signalr awal. Tidak bisa hanya menggunakan request.User.Identity.Name
xinunix

1
@ Sumant Saya sudah menyelesaikannya. Masalahnya adalah saya memasukkan app.MapSignalR();global.asax sebelum otentikasi.
Tuan Robot

38

Ini permulaannya .. Terbuka untuk saran / perbaikan.

Server

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

(Perhatikan bagaimana addChatMessagedan sendChatMessagejuga metode dalam kode server di atas)

    $(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();
        });
    });
});

Menguji masukkan deskripsi gambar di sini


Hai teman, maaf atas tanggapan yang terlambat! Tetapi bagaimana saya dapat mencegah hilangnya CONNECTIONID? Terima kasih.
Igor

5
@lgao Saya tidak tahu.
The Muffin Man

mengapa baris ini diperlukan --- Clients.Group ("2@2.com"). addChatMessage (nama, pesan); ??
Thomas

@ Thomas Saya mungkin memasukkannya demi demo. Harus ada cara lain untuk menyiarkan ke grup tertentu karena ini telah di-hardcode.
The Muffin Man

Solusi sederhana ini memecahkan masalah saya untuk mengirim pesan ke pengguna login tertentu. Sederhana, cepat dan mudah dimengerti. Saya akan memberikan suara positif untuk jawaban ini beberapa kali jika saya bisa.
Rafael AMS

5

Beginilah cara menggunakan SignarR untuk menargetkan pengguna tertentu (tanpa menggunakan penyedia apa pun):

 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
bagaimana Anda menggunakan ini contextIdClienttidak mengerti :(
Neo

2

Lihat Tes SignalR untuk fitur tersebut.

Uji "SendToUser" mengambil secara otomatis identitas pengguna yang diteruskan dengan menggunakan pustaka otentikasi owin biasa.

Skenarionya adalah Anda memiliki pengguna yang telah terhubung dari beberapa perangkat / browser dan Anda ingin mengirim pesan ke semua koneksi aktifnya.


Terima kasih sobat! Tetapi proyek versi 2.0 tidak mengkompilasi SignalR di sini. : (. Sayangnya saya tidak dapat mengaksesnya.
Igor

0

Utas lama, tetapi baru saja menemukan ini dalam sampel:

services.AddSignalR()
            .AddAzureSignalR(options =>
        {
            options.ClaimsProvider = context => new[]
            {
                new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
            };
        });
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.