SignalR - (IUserIdProvider) kullanarak belirli bir kullanıcıya mesaj gönderme * YENİ 2.0.0 *


102

Asp.Net SignalR'nin en son sürümünde, "IUserIdProvider" arayüzünü kullanarak belirli bir kullanıcıya mesaj göndermenin yeni bir yolu eklendi.

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

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

Sorum şu: Mesajımı kime gönderdiğimi nasıl bilebilirim? Bu yeni yöntemin açıklaması çok yüzeyseldir. Ve bu hata ile taslak SignalR 2.0.0 Beyanı ve derlenmiyor. Bu özelliği kullanan var mı?

Daha Fazla Bilgi: http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider

Sarılmalar.


1
SignalR ile Kimlik Doğrulama ve Yetkilendirme konusuna bakmanız gerekir. UserId, IPrincipal sağlayıcısının bir parçası olacaktır.
Gjohn

Yanıtlar:


154

SignalR, her bağlantı için ConnectionId sağlar. Hangi bağlantının kime (kullanıcıya) ait olduğunu bulmak için, bağlantı ile kullanıcı arasında bir eşleme oluşturmamız gerekir. Bu, uygulamanızda bir kullanıcıyı nasıl tanımladığınıza bağlıdır.

SignalR 2.0'da bu, IPrincipal.Identity.NameASP.NET kimlik doğrulaması sırasında ayarlanan oturum açmış kullanıcı tanımlayıcısı olan inbuilt kullanılarak yapılır .

Ancak, Identity.Name kullanmak yerine kullanıcıyla bağlantıyı farklı bir tanımlayıcı kullanarak eşlemeniz gerekebilir. Bu amaçla, bu yeni sağlayıcı, kullanıcıyı bağlantıyla eşlemek için özel uygulamanızla birlikte kullanılabilir.

IUserIdProvider kullanarak SignalR Kullanıcılarını Bağlantılarla Eşleme Örneği

Uygulamamızın userIdher kullanıcıyı tanımlamak için a kullandığını varsayalım . Şimdi belirli bir kullanıcıya mesaj göndermemiz gerekiyor. Biz var userIdve messagefakat SignalR da bizim kimliği ve bağlantı arasındaki eşleme bilmesi gerekir.

Bunu başarmak için önce aşağıdakileri uygulayan yeni bir sınıf oluşturmalıyız 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();
    }
}

İkinci adım, SignalR'ye CustomUserIdProvidervarsayılan uygulama yerine bizim kullanmasını söylemektir . Bu, hub yapılandırması başlatılırken Startup.cs içinde yapılabilir:

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

Şimdi, userIdbelgelerde belirtildiği gibi belirli bir kullanıcıya mesaj gönderebilirsiniz , örneğin:

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

Bu yardımcı olur umarım.


Merhaba arkadaşım, geç geri bildirim için özür dilerim! Ancak CustomUserIdProvider'ı oluşturan kimliğe erişmeye çalıştım, ancak "OnConnected" yöntemi aynı değil. Veritabanındaki bir Kullanıcıya nasıl bağlanırım? Teşekkür ederim!
Igor

7
MyCustomUserClass nedir?
Danny Bullis

2
"MyCustomUserClass", FindUserId yöntemini içeren özel kullanıcı sınıfınız olabilir. Bu sadece örneğin. Herhangi bir sınıfta size UserId döndüren herhangi bir yönteme sahip olabilirsiniz ve bunu burada kullanabilirsiniz.
Sumant

5
Teşekkürler @Sumant, sorunum şu oldu: b / c, OAuth 2'yi taşıyıcı jetonla uyguladığım bir Web API projesindeydim o ilk sinyal bağlantı isteğindeki başlıklar. Sadece request.User.Identity.Name kullanılamadı
xinunix

1
@Sumant Bunu zaten çözdüm. Sorun, app.MapSignalR();kimlik doğrulamasından önce global.asax koymamdı.
Sayın Robot

38

İşte bir başlangıç ​​.. Önerilere / geliştirmelere açık.

Sunucu

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

( Yukarıdaki sunucu kodundaki yöntemlerin nasıl addChatMessageve sendChatMessageaynı zamanda olduğuna dikkat edin )

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

Test yapmak görüntü açıklamasını buraya girin


Merhaba arkadaşım, geç geri bildirim için özür dilerim! Ancak CONNECTIONID kaybını nasıl önleyebilirim? Teşekkür ederim.
Igor

5
@lgao hiçbir fikrim yok.
The Muffin Man

bu satır neden gerekliydi --- Clients.Group ("2@2.com"). addChatMessage (isim, mesaj); ??
Thomas

@Thomas muhtemelen demo için ekledim. Kodlanmış olduğu için belirli bir gruba yayın yapmanın başka bir yolu olmalı.
The Muffin Man

Bu basit çözüm, oturum açmış belirli bir kullanıcıya mesaj gönderme sorunumu çözdü. Basit, hızlı ve anlaşılması kolay. Yapabilseydim bu yanıtı birkaç kez yükseltirdim.
Rafael AMS

5

Belirli bir kullanıcıyı (herhangi bir sağlayıcı kullanmadan) hedeflemek için SignarR bu şekilde kullanılır:

 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
bunu nasıl kullanıyorsun contextIdClientanlamadım :(
Neo

2

Bak SignalR Testleri özellik için.

"SendToUser" testi, normal bir owin kimlik doğrulama kitaplığı kullanılarak geçirilen kullanıcı kimliğini otomatik olarak alır.

Senaryo, birden fazla cihazdan / tarayıcıdan bağlanan bir kullanıcınız olması ve tüm aktif bağlantılarına bir mesaj göndermek istemenizdir.


Teşekkürler dostum! Ancak proje sürümü 2.0, SignalR'yi burada derlemiyor. : (. Maalesef ona erişemiyorum.
Igor

0

Eski iş parçacığı, ancak buna bir örnekte rastladım:

services.AddSignalR()
            .AddAzureSignalR(options =>
        {
            options.ClaimsProvider = context => new[]
            {
                new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
            };
        });

0

Bunu asp.net çekirdeğinde yapmaya çalışan herkes için. İddiaları kullanabilirsiniz.

public class CustomEmailProvider : IUserIdProvider
{
    public virtual string GetUserId(HubConnectionContext connection)
    {
        return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
    }
}

Herhangi bir tanımlayıcı kullanılabilir, ancak benzersiz olması gerekir. Örneğin bir ad tanımlayıcı kullanırsanız, bu, alıcıyla aynı ada sahip birden fazla kullanıcı varsa, mesajın onlara da teslim edileceği anlamına gelir. Her kullanıcıya özel olduğu için e-postayı seçtim.

Ardından hizmeti başlangıç ​​sınıfına kaydedin.

services.AddSingleton<IUserIdProvider, CustomEmailProvider>();

Sonraki. Kullanıcı kaydı sırasında talepleri ekleyin.

var result = await _userManager.CreateAsync(user, Model.Password);
if (result.Succeeded)
{
    await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, Model.Email));
}

Belirli bir kullanıcıya mesaj göndermek için.

public class ChatHub : Hub
{
    public async Task SendMessage(string receiver, string message)
    {
        await Clients.User(receiver).SendAsync("ReceiveMessage", message);
    }
}

Not: Mesajı gönderene, mesajın gönderildiği bildirilmez. Gönderenin tarafında bir bildirim istiyorsanız. SendMessageYöntemi buna değiştirin .

public async Task SendMessage(string sender, string receiver, string message)
{
    await Clients.Users(sender, receiver).SendAsync("ReceiveMessage", message);
}

Bu adımlar yalnızca varsayılan tanımlayıcıyı değiştirmeniz gerektiğinde gereklidir. Aksi takdirde, userIds veya connectionIds ileterek mesaj gönderebileceğiniz son adıma atlayın SendMessage. Daha fazlası için

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.