Wysłanie wiadomości do konkretnego użytkownika/ użytkowników

0

Cześć staram się napisać prosty chat korzystając z signalR oraz angular oraz .net core web api. Podczas dodawania wiadomości mam coś takiego :

            await db.Messages.AddAsync(message);
            await hubContext.Clients.All.BroadcastMessage(message);
            await CommitAsync();

signlaR.service.ts

import { Injectable, EventEmitter } from '@angular/core';
import * as signalR from '@aspnet/signalr';
import { Message } from '@angular/compiler/src/i18n/i18n_ast';

@Injectable({
  providedIn: 'root',
})
export class SignalRService {
  private hubConnection: signalR.HubConnection;
  signalReceived = new EventEmitter<Message>();

  constructor() {
    this.buildConnection();
    this.startConnection();
  }

  private buildConnection = () => {
    this.hubConnection = new signalR.HubConnectionBuilder()
      .withUrl('https://localhost:5001/chat')
      .build();
  };

  private startConnection = () => {
    this.hubConnection
      .start()
      .then(() => {
        console.log('Connection Started...');
        this.registerSignalEvents();
      })
      .catch((err) => {
        console.log('Error while starting connection: ' + err);

        //if you get error try to start connection again after 3 seconds.
        setTimeout(function () {
          this.startConnection();
        }, 3000);
      });
  };

  private registerSignalEvents() {
    this.hubConnection.on('BroadcastMessage', (data: Message) => {
      this.signalReceived.emit(data);
    });
  }
}

Jak moge ograniczyć to do konkretnych użytkowników.
hubContext.Clients.All.Users() <--- nie działa. Z góry bardzo dziękuje za pomoc :)

0

jasne widziałem ten artykuł tylko już na samym początku mam problem z metodą Add i Remove której nie ma w przestrzeni nazw :/
a używam paczki Microsoft.AspNetCore.SignalR.Core (1.1.0)

1

Mając definicję swojego Huba, możesz dzięki metodom OnConnectedAsync() oraz OnDisconnectedAsync() trzymać użytkowników, którzy są połączeni do konkretnego kanału:

public class YourHubName : Hub
	{
		public static ConcurrentDictionary<string, ConnectedUserInfo> ConnectedUsers = new ConcurrentDictionary<string, ConnectedUserInfo>();

		public string GetConnectionId()
		{
			return Context.ConnectionId;
		}

		public override Task OnConnectedAsync()
		{
			ConnectedUsers.TryAdd(Context.ConnectionId, new ConnectedUserInfo
			{
				ConnectionId = Context.ConnectionId,
				ClientName = // Tutaj możesz pobrać np client name z jwt: Context.User.Claims.SingleOrDefault(...)
			});

			return base.OnConnectedAsync();
		}

		public override Task OnDisconnectedAsync(Exception exception)
		{
			ConnectedUserInfo tmpMyUserInfo;

			ConnectedUsers.TryRemove(Context.ConnectionId, out tmpMyUserInfo);

			return base.OnDisconnectedAsync(exception);
		}
	}


public class ConnectedUserInfo
{
    public string ConnectionId { get; set; }
    public string ClientName { get; set; }
}

Dzięki temu trzymasz listę połączonych użytkowników. Następnie podczas wysyłania wiadomości możesz wysyłać wiadomość tylko dla konkretnych userów:


private readonly string[] _allowedClientNames = { "ClientNameToSend" };
private readonly IHubContext<YourHubName> _hubContext;

public SignalRNotificationsService(IHubContext<YourHubName> hubContext)
{
    _hubContext = hubContext;
}

public Task MessageNotification(MessageDto message)
{
    var connectionIds = UploadedFileStatusChangeHub
        .ConnectedUsers
        .Where(x => _allowedClientNames.Contains(x.Value.ClientName))
        .Select(x => x.Value.ConnectionId)
        .ToList();

    return _hubContext
        .Clients
        .Clients(connectionIds)
        .SendAsync("BroadcastMessage", message);
}
0

Działa tylko nie wiem czemu Context.User jest nullem. Próbuje znaleŹć UserId tak:

ClientName = Context.User.Claims.Where(c => c.Type == ClaimTypes.NameIdentifier).First().Value

Lecz zwraca null :/

1

Wygląda na to, jakbyś miał miał zalogowanego użytkownika ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1