Как получить UserID для отправки личного сообщения через SignalR.Core 3.0 от Xamarin - PullRequest
1 голос
/ 29 октября 2019

Я пытаюсь создать чат в Xamarin, который отправляет личные сообщения. На данный момент мне удалось отправить сообщения определенной группе или всем пользователям, но я не знаю, как со стороны клиента я получаю идентификатор пользователя для отправки личного сообщения.

Я пробовал документацию Microsoftно все, что он показывает, это как настроить на стороне сервера, но нет примеров того, как это будет на стороне клиента.

Я пробовал с этой документацией: https://docs.microsoft.com/en-us/aspnet/core/signalr/groups?view=aspnetcore-2.1

https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections#IUserIdProvider

Но я не могу найти документацию или пример того, как найти идентификатор пользователя со стороны клиента, чтобы можно было отправить сообщение, или, возможно, у меня плохое представление о том, как следует решить проблему.

Сторона сервера:

public class ChatHub : Hub
{

    public async Task JoinChat(string user)
    {
        await Clients.All.SendAsync("JoinChat", user);
    }

    public async Task LeaveChat(string user)
    {
        await Clients.All.SendAsync("LeaveChat", user);
    }

    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }

    public void BroadcastMessage(string name, string message)
    {
        Clients.All.SendAsync("broadcastMessage", name, message);
    }

    public void Echo(string name, string message)
    {
        Clients.Client(Context.ConnectionId).SendAsync("echo", name, message + " (echo from server)");
    }

    public async Task AddToGroup(string groupName, string user)
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);

        await Clients.Group(groupName).SendAsync("Entered", user);
        //await Clients.Group(groupName).SendAsync("Entered", "_SYSTEM_", $"{user} joined {groupName} with connectionId {Context.ConnectionId}");
    }

    public async Task RemoveFromGroup(string groupName, string user)
    {
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
        //await Clients.Client(Context.ConnectionId).SendAsync("Left", "_SYSTEM_", $"{user} leaved {groupName}");
        await Clients.Group(groupName).SendAsync("Left", user);
        //await Clients.Group(groupName).SendAsync("Left", "_SYSTEM_", $"{user} leaved {groupName}");
    }

    public async Task SendMessageGroup(string groupName, string user, string message)
    {
        await Clients.Group(groupName).SendAsync("ReceiveMessage", user, message);
    }
    //**//

    public void SendGroups(string name, IReadOnlyList<string> groups, string message)
    {
        Clients.Groups(groups).SendAsync("echo", name, message);
    }

    public void SendGroupExcept(string name, string groupName, IReadOnlyList<string> connectionIdExcept, string message)
    {
        Clients.GroupExcept(groupName, connectionIdExcept).SendAsync("echo", name, message);
    }

    public void SendUser(string name, string userId, string message)
    {
        Clients.User(userId).SendAsync("echo", name, message);
    }

    public void SendUsers(string name, IReadOnlyList<string> userIds, string message)
    {
        Clients.Users(userIds).SendAsync("echo", name, message);
    }

}
public class CustomUserIdProvider : IUserIdProvider
{
    public virtual string GetUserId(HubConnectionContext connection)
    {
       // return connection.User?.Identity?.Name;
        return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
    }
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
    {
        builder.AllowAnyMethod()
            .AllowAnyHeader()
            .WithOrigins("http://localhost:5002");
    }));
    services.AddSignalR();
    services.AddSingleton<IUserIdProvider, CustomUserIdProvider>();
}

Сторона клиента:

Взято изДжеймс Монтемагно из: https://github.com/jamesmontemagno/XamChat

public class ChatService
{
    public event EventHandler<MessageEventArgs> OnReceivedMessage;
    public event EventHandler<MessageEventArgs> OnEnteredOrExited;
    public event EventHandler<MessageEventArgs> OnConnectionClosed;

    HubConnection hubConnection;
    Random random;

    bool IsConnected { get; set; }
    Dictionary<string, string> ActiveChannels { get; } = new Dictionary<string, string>();


    public void Init(string urlRoot, bool useHttps)
    {
        random = new Random();

        var port = (urlRoot == "localhost" || urlRoot == "10.0.2.2") ?
            (useHttps ? ":5001" : ":5000") :
            string.Empty;

        var url = $"http{(useHttps ? "s" : string.Empty)}://{urlRoot}{port}/hubs/chat";
        hubConnection = new HubConnectionBuilder()
        .WithUrl(url)
        .Build();

        hubConnection.Closed += async (error) =>
        {
            OnConnectionClosed?.Invoke(this, new MessageEventArgs("Connection closed...", string.Empty));
            IsConnected = false;
            await Task.Delay(random.Next(0, 5) * 1000);
            try
            {
                await ConnectAsync();
            }
            catch (Exception ex)
            {
                // Exception!
                Debug.WriteLine(ex);
            }
        };

        hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            OnReceivedMessage?.Invoke(this, new MessageEventArgs(message, user));
        });

        hubConnection.On<string>("Entered", (user) =>
        {
            OnEnteredOrExited?.Invoke(this, new MessageEventArgs($"{user} entered.", user));
        });


        hubConnection.On<string>("Left", (user) =>
        {
            OnEnteredOrExited?.Invoke(this, new MessageEventArgs($"{user} left.", user));
        });


        hubConnection.On<string>("EnteredOrLeft", (message) =>
        {
            OnEnteredOrExited?.Invoke(this, new MessageEventArgs(message, message));
        });
    }

    public async Task ConnectAsync()
    {
        if (IsConnected)
            return;

        await hubConnection.StartAsync();
        IsConnected = true;
    }

    public async Task DisconnectAsync()
    {
        if (!IsConnected)
            return;

        try
        {
            await hubConnection.DisposeAsync();
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }

        ActiveChannels.Clear();
        IsConnected = false;
    }

    public async Task LeaveChannelAsync(string group, string userName)
    {
        if (!IsConnected || !ActiveChannels.ContainsKey(group))
            return;

        await hubConnection.SendAsync("RemoveFromGroup", group, userName);

        ActiveChannels.Remove(group);
    }

    public async Task JoinChannelAsync(string group, string userName)
    {
        if (!IsConnected || ActiveChannels.ContainsKey(group))
            return;

        await hubConnection.SendAsync("AddToGroup", group, userName);
        ActiveChannels.Add(group, userName);

    }

    public async Task SendMessageAsync(string group, string userName, string message)
    {
        if (!IsConnected)
            throw new InvalidOperationException("Not connected");

        await hubConnection.InvokeAsync("SendMessageGroup",
                group,
                userName,
                message);
    }

    public async Task SendMessageUserAsync(string group, string userName, string message)
    {
        if (!IsConnected)
            throw new InvalidOperationException("Not connected");

        await hubConnection.InvokeAsync("SendUser",
                userName,
                "10",
                message);
    }
}

1 Ответ

0 голосов
/ 29 октября 2019

Чего вам не хватает, так это сопоставления соединений с пользователями. Я хотел бы создать, например, динамический список пользователей и отображать их каждый раз, когда пользователь подключается. Например, имея метод для возврата идентификатора соединения:

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

И после получения идентификатора соединения вы можете вызвать метод для сопоставления пользователя с соединением. Поэтому, если вам нужно отправить сообщение конкретному пользователю, вы можете выполнить поиск пользователя в вашем списке и получить идентификатор соединения этого конкретного пользователя, чтобы вы могли отправить ему сообщение, например:

Clients.Client(connectionId).SendAsync(from, to, message);

Выможете прочитать эту документацию по этому вопросу, хотя для старой SignalR вы можете использовать ту же логику и адаптировать ее для своих нужд.

...