11.050 messaggi dal 09 febbraio 2002
Contributi
Ciao,


lo scenario sarà quello di un utente loggato che potrà accedere ad una chat fine a se stessa, ma nel sito esistono altre Chat che non hanno nulla in comune tra di loro

Ok, grazie per il chiarimento. Ma gli utenti possono scegliere a quale/i chat partecipare oppure gli viene imposta?
Comunque, la soluzione consiste proprio nell'usare i Group. Tutti i client che si trovano nella stessa chat apparterranno allo stesso Group.


Ora come cosa vorrei capire se devo creare una chiamata all'hub unica per tutte le chat

Predisponi un solo Hub. In esso crea un metodo SendMessage che i clienti invocheranno quando vogliono inviare i messaggi. Invece, sul client predisponi una funzione receiveMessage che verrà invocata dal server per recapitare i messaggi arrivati da altri utenti. Ecco un esempio, supponengo che l'utente non possa scegliere a quale chat partecipare.

   public class ChatHub : Hub
    {
        public override Task OnConnected()
        {
            return base.OnConnected();

            //Imponiamo la partecipazione ad un gruppo a questo utente.
            //Determiniamo il gruppo a cui deve appartenere in base al suo username
            //ma tu puoi usare altre logiche
            var gruppo = DeterminaGruppoPerUtente(Context.User.Identity.Name);
            //Lo aggiungiamo automaticamente al gruppo
            Groups.Add(Context.ConnectionId, gruppo);

            //Eventualmente qui facciamo una query al database
            //e gli mandiamo tutti i messaggi pregressi di quel gruppo
            //(non necessariamente tutti, magari gli ultimi 100)
            foreach (var messaggio in messaggi)
            {
                //La funzione receiveMessage dovrà esistere sul client
                Clients.Caller.ReceiveMessage(messaggio);
            } 
        }

        //I client invocheranno il metodo SendMessage quando vogliono inviare un messaggio
        public void SendMessage(string messaggio)
        {
            //Ancora una volta, determiniamo qual è il gruppo dell'utente in base al suo username
            var gruppo = DeterminaGruppoPerUtente(Context.User.Identity.Name);
            //Qui salvi il messaggio nel database
            //E poi lo recapiti agli altri nello stesso gruppo di questo utente
            //invocando la funzione receiveMessage che dovrà esistere sul client
            Clients.OthersInGroup(gruppo).ReceiveMessage(messaggio);
        }
    }


In alternativa, se i client scelgono a quali chat partecipare, il metodo SendMessage può accettare il nome del gruppo come secondo parametro.


Inoltre siccome le sessioni di queste chat sono molto lunghe volevo sapere se avevo problemi di memoria, per esempio dopo 100 messaggi devo fare qualcosa

Sì, effettivamente non ha senso caricare migliaia di messaggi se poi l'utente non li legge. Devi essere abile tu nel caricarli on-demand quando l'utente scrolla indietro nella storia. Quando lo scroll arriva al messaggio più vecchio caricato, chiedi al server di darti altri 100 messaggi ancora più vecchi. Magari predisponi un metodo GetOldMessagges(DateTime startingFrom) così gli dai i messaggi più vecchi di una certa data/ora.

ciao,
Moreno

Enjoy learning and just keep making
15 messaggi dal 23 maggio 2014
Ciao grazie Moreno,

Allora la Chat non è imposta, ma sarà l'utente a cliccare sul link ed entrare in una Chat, una volta entrato i messaggi vecchi vengono popolati da una query del database, poi successivamente faccio una chiamata come hai descritto tu ossia tramite la funzione hub SendMessage.

quindi partendo dopo l'invocazione del database, posso creare un una variabile che mi faccia da contatore (magari per 100 messaggi) dopo di che rifaccio l'invocazione della query di select del database. Questo ovviamente se c'è bisogno considerando la questione di una lunga sessione della Chat.

Inoltre quando viene chiamata la funzione all'hub per inviare a tutti il messaggio appena scritto viene anche fatto in insert nel database.

Detto ciò mi conviene usare per ogni Chat la creazione di un gruppo differente (però come detto decide l'utente a quale entrare) e la funzione descritta da te ossia SendMessage?

Ancora io Quando chiamo la mia funzione Hub ho inserito:
        Dim context As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of ChatHub)()
        context.Clients.All.DisplayStatus(username, testo, TipoMessaggio, InviaA)



quindi mi creo la variabile context (ovviamente qui ancora devo modificare per creare gruppi)....

Ora tu usi la funzione Overrides OnConnected, volevo capire se utile al mio scopo cioè l'utente clicca sul link per entrare per esempio in Chat_1, ma poi esce da quel link tornando nella home e clicca per entrare in una chat differente, facciamo Chat_2, ora l'utente verrà cancellato dalla Chat_1 oppure viene aggiunto in tutte le Chat dove entra? nel caso come si può gestire una situazione del genere? perché vedo la funzione remove di group però dove mi conviene invocarla nel caso l'utente rimane connesso, ma si vuole spostare ?

Vedo la tua guida su SignalR dove fai
public void JoinGroup(string groupName)
{
  //  fornisco il ConnectionId che identifica il client e il nome del gruppo
  Groups.Add(Context.ConnectionId, groupName);
}


questa join in js che sta sotto deve essere inserita dopo aver inviato il comando start dell'hub?
$.connection.nomeHub.server.joinGroup("Nuoto");
$.connection.nomeHub.server.joinGroup("Scherma");


quindi magari in ogni Chat inserisco questa riga di js inviando il nome della Chat di connessione, ma come posso gestire l'uscita nel caso l'utente va in un'altra pagina e dopo un poco decide di entrare in una chat diversa dalla prima? magari facendolo uscire da tutte le altre dove è connesso e facendo il join nella nuova.
Modificato da Cicico il 19 gennaio 2018 16.22 -
11.050 messaggi dal 09 febbraio 2002
Contributi
Ciao Ciro,
Detto ciò mi conviene usare per ogni Chat la creazione di un gruppo differente

Assolutamente sì, dovresti creare un gruppo per ogni chat. Al momento stai recapitando i messaggi ai client in questo modo: context.Clients.All.... ma questo è sbagliato perché un dato messaggio deve essere recapitato solo ad un gruppo. Quindi dovrai usare Clients.OthersInGroup come vedevi nell'esempio della funzione SendMessage.


Quando chiamo la mia funzione Hub ho inserito:
Dim context As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of ChatHub)()

Questo codice tipicamente lo usi per ottenere il contesto dell'Hub dal di fuori dell'Hub (ad esempio, in un Controller di ASP.NET MVC).
Tu in realtà non hai bisogno di usare questa tecnica perché il client invia il suo messaggio usando la funzione SendMessage definita nell'hub stesso. Sei già nell'hub, non hai bisogno di usare GlobalHost.ConnectionManager.GetHubContext. Come vedi, infatti, ho potuto inoltrare il messaggio a tutti gli altri utenti dello stesso gruppo facendo semplicemente:
public void SendMessage(string messaggio, string groupId)
{
  //Qui salva il messaggio nel db
  //e poi inoltralo ai client dello stesso gruppo
  Clients.OthersInGroup(groupId).ReceiveMessage(messaggio);
}

Questa funzione SendMessage l'ho leggermente modificata dato l'utente decide egli stesso a quale gruppo unirsi. Quindi, nell'invocare il SendMessage, fornirà sia il messaggio che l'id del gruppo (cioè l'id della chat) in cui si trova.


Ora tu usi la funzione Overrides OnConnected, volevo capire se utile al mio scopo

No, non è utile dato che non c'è la necessita di aggiungere l'utente ad un gruppo forzatamente.
Quando l'utente cliccherà una delle chat, allora invoca un metodo dell'hub che lo unirà a tale gruppo, proprio come il JoinGroup che hai trovato nell'esempio.
Quando esce dalla chat, allo stesso modo invoca un eventuale metodo LeaveGroup per farlo uscire dal gruppo, in modo che non riceva più messaggi.


questa join in js che sta sotto deve essere inserita dopo aver inviato il comando start dell'hub?

Non subito, ma solo quando l'utente clicca il link per entrare in una chat. Il fatto di appartenere ad un gruppo di consentirà di ricevere dal server tutti i messaggi di quel gruppo.
Secondo me, nella funzione JoinGroup dell'hub puoi andare a selezionare gli ultimi 100 messaggi del gruppo e mandarglieli invocando il ReceiveMessage sul client.

public void JoinGroup(string groupId)
{
  Groups.Add(Context.ConnectionId, groupId);
  //Qui select al database per estrarre gli ultimi 100 messaggi
  foreach (var messaggio in ultimi100Messaggi) {
    //Fornisco anche il groupId come parametro, nel caso in cui l'utente abbia acceduto
    //a più chat contemporaneamente. Servirà lato client per capire in quale delle chat aperte
    //andarlo a visualizzare
    Clients.Caller.ReceiveMessage(messaggio.Mittente, messaggio.Testo, messaggio.Tipo, groupId);
  }
}



come posso gestire l'uscita nel caso l'utente va in un'altra pagina e dopo un poco decide di entrare in una chat diversa dalla prima

Di solito non devi fare niente perché, se cambia pagina, l'utente presto verrà disconnesso automaticamente e SignalR lo rimuoverà a qualsiasi gruppo di fosse aggiunto.

Quando entra di nuovo nella pagina di selezione delle chat, stabilirà una nuova connessione e tu lo riaggiungerai ad un gruppo nel momento in cui clicca una delle chat in elenco.

Casomai metti un bottone "Chiudi chat". Quando l'utente lo clicca, invoca una funzione LeaveGroup sull'hub in cui lo rimuovi esplicitamente dal gruppo.

ciao,
Moreno

Enjoy learning and just keep making
15 messaggi dal 23 maggio 2014
Ciao, tutto molto interessante, inoltre sono andato a vedere la guida sul sito per i gruppi di SignalR (fatta proprio da te), quindi ho trasformato la chiamata client:
           var job = $.connection.chatHub;


            job.client.renewData = function () {
                $('#tbl').empty();
                $('#BtnInvia').attr("Enabled", true);
            };

in
            job.server.displayStatus = function (username, Messaggio, TipoMessaggio, InviaA) {
                var $tbl = $('#tbl');

                if (Number(InviaA) == 0 && Number(TipoMessaggio) == 1) {
                    $tbl.append(' <tr><td colspan="2">' + username + '</td><td>' + Messaggio + '</td></tr>');
                } 
                $('#BtnInvia').prop("Enabled", true);
            };



Mi sono portato tutti i parametri proprio nel verificare che fossero passati tutti correttamente. C'è la possibilità di inviare più parametri al server al server ?

Inoltre ho fatto richiesta di inserimento nel gruppo così
            $.connection.hub.start().done(function () {
                $.connection.chatHub.server.joinGroup("Chat_1");
            });


mentre nell'hub ho impostato il richiamo proprio come hai fatto tu.
Clients.Group("Chat_1").DisplayStatus(username, testo, TipoMessaggio, InviaA)


però quando invio il messaggio non viene notificato a nessuno, neanche a me stesso, e non riscontro errori in console, dove sto sbagliando? nell'hub dove nella sub di chiamata faccio server.displayStatus devo invocare anche il metodo di ricezione messaggio oppure devo creare un'altra sub per ricevere i messaggi? inoltre come detto anche per la prima sub i parametri passati possono essere più di uno?

___________________

inoltre la questione che volevo porti per una questione di logica è:

Il mio progetto è formato da n Chat, che alla fine saranno ben definite, quindi se mi serviranno 10 Chat quelle saranno ed è difficile che aumentino.

Inoltre tu mi hai fornito una logica dove io caricavo con una SQL select i messaggi da inviare al server che poi dovrò sparare a video all'utente che sta in quella determinata chat.

Io invece avevo pensato che nel Load page di quella determinata chat facevo una select che mi caricavo i messaggi di quella chat (ogni chat ha una sua tabella separata) e solo successivamente utilizzavo l'hub per agganciare altri messaggi in quella Chat. Ora con questa logica posso creare nel mio Hub principale tanti sotto hub con nomi differenti che ereditano hub, in modo da fare chiamate differenti per ogni hub (inoltre vorrei capire se facendo in questo modo la funzione reciveMessage può rimanere uguale per tutti o cmq devo cambiare il nome anche se mi connetto ad hub con nomi differenti) oppure mi conviene la logica dei gruppi come mi hai esposto tu all'inizio?


grazie ancora,
Ciao,
Ciro
Modificato da Cicico il 21 gennaio 2018 10.29 -
Modificato da Cicico il 21 gennaio 2018 13.46 -
11.050 messaggi dal 09 febbraio 2002
Contributi
Ciao Ciro,
guarda, ti mando un'applicazione funzionante in VB.NET. Prendi spunto da questa.
https://github.com/BrightSoul/aspnet-signalr-groups-demo


Io invece avevo pensato che nel Load page di quella determinata chat facevo una select che mi caricavo i messaggi di quella chat (ogni chat ha una sua tabella separata) e solo successivamente utilizzavo l'hub per agganciare altri messaggi in quella Chat

Puoi fare anche così ma perché inventare un secondo sistema di recapito di messaggi quando ne hai già uno?
Nell'applicazione demo che ti ho linkato riutilizzo appunto la funzione ReceiveMessages.
Lato client uso KnockoutJS per presentare i dati, così il codice resta tutto più leggibile.

ciao,
Moreno
Modificato da BrightSoul il 22 gennaio 2018 22.39 -

Enjoy learning and just keep making
15 messaggi dal 23 maggio 2014
Ciao Moreno, e grazie ancora per la pazienza, ho letto il tuo codice è l'ho utilizzato per la parte che mi interessava (come detto la Chat viene scelta dall'utente, ma sono disgiunte una dall'altra), è sembra funzionare bene, volevo solo chiedere solo se in questo modo c'è la possibilità di duplicazioni di messaggi inviati oppure viene gestito bene l'invio sul server!?!?

Ancora una cosa, per inviare un messaggio privato ho strutturato il codice in modo che quando la mia variabile TipoMessaggio sarà uguale a 2 allora deve scrivermi a chi ha mandato il messaggio "hai scritto a ...", mentre chi deve ricevere questo messaggio "l'utente pippo ti ha scritto...", per fare ciò non ho strutturato ne una select, ne utenti Online in quel Gruppo Chat, ma l'utente che deve madnare il messaggio scrive: @NomeUtenteRicevente@Messaggio , ma in questo modo mi appare solo a chi manda il messaggio e chi lo deve ricevere non viene visualizzato nulla.

inoltre per invocare il metodo al click del tasto submit ho fatto in questo modo, me ne consigli uno più pulito o va bene?
                Dim invia As ChatHub
                invia.SendMessage(message)


Inoltre è possibile ricavare la lista degli utente di quel gruppo o magari associando il nome utente all'Id di connessione di quell'utente? ovviamente che poi sia possibile modificarlo man mano che escono o entrano.

Inoltre vedo che tu hai usato un Framework, però io volevo dirigermi verso l'apprendimento di angularJs, però voglio un consiglio da te e nel caso se c'è una documentazione che posso vedere stesso su aspitalia che ovviamente sia legato anche al .Net, siccome voglio capire come connettere, su certi aspetti, la parte code behind con il front.

Ciao Ciro
Modificato da Cicico il 24 gennaio 2018 20.10 -
Modificato da Cicico il 24 gennaio 2018 21.40 -
Modificato da Cicico il 25 gennaio 2018 15.08 -
11.050 messaggi dal 09 febbraio 2002
Contributi
Ciao Ciro,


volevo solo chiedere solo se in questo modo c'è la possibilità di duplicazioni di messaggi inviati oppure viene gestito bene l'invio sul server!?!?

Sì, viene gestito bene. Hai osservato qualche duplicazione o hai motivi per pensare che potrebbero risultare messaggi duplicati?


ma l'utente che deve madnare il messaggio scrive: @NomeUtenteRicevente@Messaggio

Ok, cerca di fare in modo che sia @NomeUtenteRicevente e non @NomeUtenteRicevente@, così sarà più usabile. Bravo per aver pensato a questa prassi comune che consiste nell'usare il simbolo @ come prefisso per menzionare qualcuno.

Puoi usare questa espressione regolare per catturare il nome dell'utente (da personalizzare come vuoi). Il nome utente deve essere ad inizio riga e il messaggio sarà separato da uno spazio (es. @mario.rossi Come stai?)
^@([\w_\.\-]+)



ma in questo modo mi appare solo a chi manda il messaggio e chi lo deve ricevere non viene visualizzato nulla.

Dev'essere che non lo stai inviando correttamente. Che codice usi? Hai il connectionID del destinatario?


Inoltre è possibile ricavare la lista degli utente di quel gruppo o magari associando il nome utente all'Id di connessione di quell'utente?

Nell'OnConnected, puoi aggiungere automaticamente l'utente ad un gruppo che porta il suo nome. In questo modo puoi usare il nome dell'utente per inviargli il messaggio, anziché doverti memorizzare la corrispondenza tra ogni ConnectionID e username. Recapitagli il messaggio in questo modo.
Clients.Group(nomeUtenteDestinatario).ReceiveMessage(messaggio)



inoltre per invocare il metodo al click del tasto submit ho fatto in questo modo, me ne consigli uno più pulito o va bene?

No, cerca di evitare i submit, non devi assolutamente far ricaricare la pagina. Guarda la mia demo: la pagina non si ricarica neanche quando si cambia chat. Se devi inviare un messaggio usa sempre i metodi dell'hub di SignalR. Per esempio, per i messaggi privati puoi predisporre un nuovo metodo chiamato "SendPrivateMessage".


Inoltre vedo che tu hai usato un Framework

E' solo knockoutjs, una semplice (ma potente) libreria per separare logica da markup. Tu se vuoi puoi usare tranquillamente angularjs.


se c'è una documentazione che posso vedere stesso su aspitalia che ovviamente sia legato anche al .Net, siccome voglio capire come connettere, su certi aspetti, la parte code behind con il front.

Tipicamente non si usa WebForms, ma ASP.NET WebAPI per la parte backend. Fai una ricerca per angular2 qui:
http://www.html5italia.com/ricerca/super.aspx?key=angular2

ciao,
Moreno

Enjoy learning and just keep making
15 messaggi dal 23 maggio 2014
Ciao Moreno,


Sì, viene gestito bene. Hai osservato qualche duplicazione o hai motivi per pensare che potrebbero risultare messaggi duplicati?


No, era solo semplice curiosità


Ok, cerca di fare in modo che sia @NomeUtenteRicevente e non @NomeUtenteRicevente@, così sarà più usabile. Bravo per aver pensato a questa prassi comune che consiste nell'usare il simbolo @ come prefisso per menzionare qualcuno.

Puoi usare questa espressione regolare per catturare il nome dell'utente (da personalizzare come vuoi). Il nome utente deve essere ad inizio riga e il messaggio sarà separato da uno spazio (es. @mario.rossi Come stai?)
^@([\w_\.\-]+)



Oddei non sono pratico con la regexpression, infatti ho utilizzato questo modello proprio per cercare nella stringa proprio la dicitura sopra elencata al punto 0 e in quel caso mandavo un msg privato.


Dev'essere che non lo stai inviando correttamente. Che codice usi? Hai il connectionID del destinatario?

Nell'OnConnected, puoi aggiungere automaticamente l'utente ad un gruppo che porta il suo nome. In questo modo puoi usare il nome dell'utente per inviargli il messaggio, anziché doverti memorizzare la corrispondenza tra ogni ConnectionID e username. Recapitagli il messaggio in questo modo.
Clients.Group(nomeUtenteDestinatario).ReceiveMessage(messaggio)


Il problema che la Chat è accessibile a tutti, ed è per questo motivo che ho creato la dicitura sopra descritta con la @... quindi dovrei creare una corrispondenza di ConnectionId? attraverso una classe e come faccio a creare una memorizzazione globale?


No, cerca di evitare i submit, non devi assolutamente far ricaricare la pagina. Guarda la mia demo: la pagina non si ricarica neanche quando si cambia chat. Se devi inviare un messaggio usa sempre i metodi dell'hub di SignalR. Per esempio, per i messaggi privati puoi predisporre un nuovo metodo chiamato "SendPrivateMessage".


Diciamo che stavo utilizzando l'update Panel per questo usavo il submit, ma sto cercando di cambiare il tutto attraverso la chiamata con un web method


        function controlloValori() {
            if ($("#TxtMessaggio").val() != '') {

                $.ajax({
                        type: "POST",
                        url: "Chat.aspx/ChatSend",
                        data: "{ _username: '" + $("#HiddenField1").val() + "', testo: '" + $("#TxtMessaggio").val() + "', Utente: " + <%=User.Identity.Name%> + "}",
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        success: function (data) {
                            //alert(data.d.Username);

                            $.connection.chatHub.server.sendMessage(data.d).done(function () {
                                $("#TxtMessaggio").val('');
                                scrollToBottom();
                            });
                        },
                        failure: function (response) {
                            alert(response.d);
                        },
                        error: function (jqXHR, error, errorThrown) {
                            if (jqXHR.status && jqXHR.status == 400) {
                                alert(jqXHR.responseText);
                            } else {
                                alert(jqXHR.responseText);
                            }
                        }
                });

                $('#BtnInvia').prop("Enabled", false);
                return false;
            } else {
                return true;
            }
        }



dove l'username è il nickname dell'utente, testo è il messaggio inviato, mentre utente è l'autenticazione del login (è l'id e non il suo nome utente).

mi viene restituito questo errore: Uncaught TypeError: $.connection.chatHub.server.sendMessage is not a function

Il sendMessage è scritto così
    Public Sub SendMessage(message As messaggi)
        message.Messaggio = WebUtility.HtmlEncode(message.Messaggio)
        'Dim context As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of ChatHub)()

        'Poi lo inoltriamo agli altri utenti del gruppo
        Clients.Group("Chat_1").ReceiveMessage(message)
        If message.TipoMessaggio = 2 Then Clients.Group("Chat_1").User(message.InviaA).ReceiveMessage(message)

    End Sub


Inoltre ti faccio vedere come ho impostato nel btnInvia la ricerca del messaggio privato:
        Dim _Cstr As Boolean = testo.Contains("@")
        If _Cstr AndAlso (testo.IndexOf("@") = 0) Then
            Dim sussurro As String() = Split(testo, "@")
            If sussurro.Length >= 3 Then
                _InviaA = StrConv(sussurro(1), VbStrConv.ProperCase)
                testo = sussurro(2)
                _TipoMessaggio = 2
            End If
        End If



cosa sbaglio?

sarebbe più snello con la regular expression?

Ciao ciro.
Modificato da Cicico il 25 gennaio 2018 22.31 -
Modificato da Cicico il 26 gennaio 2018 23.00 -
Modificato da Cicico il 26 gennaio 2018 23.02 -

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.