Renan
Renan

Reputation: 121

SignalR - Send message AllExcept() dont work (Aspnet Core 2.1)

I'm trying to send a message to all users who are connected to the hub, except for the user who made the request to the controller, but the AllExcept () method is sending a message to all users.

I will explain what I have done so far.

I have an Aspnet Core 2.1 application using signalR 3.18 (I'm not sure of the version but it's> 3)

Here is my Hub class

public class MesHub : Hub
    {
        public async Task Cadastrar()
        {
            await Clients.All.SendAsync("ReceberCadastro", true, "deu certo");
        }

        public override Task OnConnectedAsync()
        {
            string name = Context.User.Identity.Name;

            Groups.AddToGroupAsync(Context.ConnectionId, name);

            return base.OnConnectedAsync();
        }
    }

I'm using the hub via dependency injection in the controller, so follow my controller. I will not post my entire controller, just a part.

private readonly TipoEstoqueService _context;
        private readonly UsuarioService _userContext;
        private readonly IHubContext<MesHub> _hubContext;

        public TipoEstoqueController(TipoEstoqueService context, 
            UsuarioService userContext, 
            IHubContext<MesHub> hubContext)
        {
            _context = context;
            _userContext = userContext;
            _hubContext = hubContext;
        }


[HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create(TipoEstoque obj)
        {
            string idUser = this.User.Identity.Name;
            /*verifica se post é valido. Se  o js estiver desabilitado no navegador do usuario
            ele consegue dar post vazio, esse if serve para previnir isso*/
            if (!ModelState.IsValid)
            {
                return View(obj);//teve algum campo q n foi preenchido
            }

            if (await _context.VerificaNome(obj.Nome, -1)) // se ja existe o nome
            {
                await _hubContext.Clients.Group(idUser).SendAsync("TipoEstoqueCadastradoFalha", true, "Este Nome já existe");
                return Json("Erro: Este Nome já existe");
            }
            
            try
            {
                await _context.InsertAsync(obj);
                
                //informa ao usuario q esta cadastrando, q o cadastro funcionou
                await _hubContext.Clients.Group(idUser).SendAsync("TipoEstoqueCadastradoSucesso", true, "O Tipo do Estoque foi adicionado com sucesso.");
                //atualiza a lista pra tds
                await _hubContext.Clients.All.SendAsync("AtualizaListagemTipoEstoque", true);
                //informa para tds q foi feito um novo cadastro
                await _hubContext.Clients.AllExcept(idUser).SendAsync("NovoTipoEstoqueFoiCadastradoSucesso", true, idUser+" cadastrou um Tipo de Estoque.");
                
            }
            catch (Exception)
            {
                await _hubContext.Clients.Group(idUser).SendAsync("TipoEstoqueCadastradoFalhaException", true, "Houve uma exceção ao tentar cadastrar, tente novamente.");
            }
            
            return Json("Success");
        }

In my controller inside the create method and inside the try, I send messages through SignalR, all sending works normally, but this section is not doing what it should.

//informa para tds q foi feito um novo cadastro
                await _hubContext.Clients.AllExcept(idUser).SendAsync("NovoTipoEstoqueFoiCadastradoSucesso", true, idUser+" cadastrou um Tipo de Estoque.");

In my understanding this excerpt should send the message to all users with the exception of those who called the create method, however this is not happening. The message is sent to everyone without exception.

In my _Layout.cshtml I have the following code to connect to the Hub

<script>
    var connection = new signalR.HubConnectionBuilder().withUrl("/MesHub").build();
    var usuarioConectado;
    function ConnectionStart() {
        Object.defineProperty(WebSocket, 'OPEN', { value: 1, });
        connection.start().then(function () {
            $(".status-user").css({ backgroundColor: '#00dc00' });
            usuarioConectado = true;
        }).catch(function (err) {
            console.error(err.toString());
            console.log(usuarioConectado);
            $(".status-user").css({ backgroundColor: '#ff0303' });
            setTimeout(ConnectionStart(), 5000);
        });
    }

    // Essa linha tenta reconectar ao hub caso a conexão caia do lado do cliente
    connection.onclose(async () => { await ConnectionStart(); });

    ConnectionStart();
</script>

Here I have a View called Index.cshtml that awaits messages from the Hub

//Cadastro realizado com sucesso
    connection.on("TipoEstoqueCadastradoSucesso", function (sucesso, msg) {
        if (sucesso) {
            swal({
                title: "Sucesso!",
                text: "Item criado com sucesso.",
                confirmButtonColor: "#fff0",
                type: "success",
                timer: 1300
            });
            $("#divModal").modal('hide');
        }
    });

    //informa a tds q foi feito um novo cadastro
    connection.on("NovoTipoEstoqueFoiCadastradoSucesso", function (sucesso, msg) {
        if (sucesso) {
            new PNotify({
                title: 'Adicionado!',
                text: msg,
                type: 'success',
                addclass: 'alert-styled-left alert-arrow-left',
            });
        }
    });

Can someone please tell me what I'm doing wrong ??

If any information is missing, please tell me that I will post.

Upvotes: 1

Views: 307

Answers (1)

Wellington J&#250;nior
Wellington J&#250;nior

Reputation: 264

The userId in Identity is different from ConnectionId in context of Hub.

await _hubContext.Clients.AllExcept(idUser)... 

This idUser above is an unknown for Hub.

You need associate the UserId of Identity on the Connection Id of Hub:

1 - Declare the class below:

public class CustomUserIdProvider : IUserIdProvider
{
    public virtual string GetUserId(HubConnectionContext connection)
    {
        return connection.GetHttpContext().User?.FindFirst(ClaimTypes.NameIdentifier)?.Value
    }
}

In your DI settings, add this line:

services.AddSingleton<IUserIdProvider, CustomUserIdProvider>();

After this, test again!

Note: I think that you don't need this line in override of OnConnectedAsync:

 Groups.AddToGroupAsync(Context.ConnectionId, name);

For send message for specific User you can write this (where idUser is an id of Identity):

await _hub.Clients.Users(idUser).SendAsync ...

Upvotes: 0

Related Questions