11 messaggi dal 23 maggio 2014
Salve a tutti,

volevo alcune delucidazioni in merito a quanto sto facendo prima di procedere, ovviamente sto prendendo documentazione tra i vari forum.

Premetto che ho strutturato la mia soluzione in un primo progetto (webForms) dove effettuo le chiamate ad un secondo progetto nella stessa soluzione che funge da Web API.... la ragione della separazione della Web API è semplicemente per esportarlo nel caso mi servisse in un'altra soluzione in modo da avere il codice server side separato, quindi nel primo progetto faccio richiamo al secondo progetto (API).

Ora la mia domanda centrale sta nel fatto di utilizzare un control per la messaggistica real-time, quindi quale mi consigliate?

Io ho visto la documentazione del nuget ASP.NET SignalR, ma volevo sapere se ci sono altre opzioni disponibili per la tecnologia real-time. Inoltre se è possibile utilizzare un DB SQL o conviene utilizzare un altro metodo per immagazzinare le conversazioni in quanto ho necessità di fare un salvataggio di tali informazioni, la questione se usare un SQL o meno sta nella problematica delle risorse, siccome ha bisogno di una continua chiamata.

Spero di essere stato chiaro,
ringrazio tutti in anticipo per l'aiuto.
10.326 messaggi dal 09 febbraio 2002
Contributi
Ciao,
ASP.NET SignalR è un'ottima soluzione, dovresti assolutamente provarla. Qui su Aspitalia ne abbiamo parlato e ne torneremo a parlare quando sarà rilasciato per ASP.NET Core.
http://tags.aspitalia.com/SignalR/

ASP.NET SignalR può usare WebSockets come trasporto se ti doti di IIS8 o superiore. Come saprai, è uno standard del web che serve a stabilire connessioni bidirezionali e persistenti tra client e server, sopra le quali viaggeranno i messaggi in tempo reale. Lo puoi usare tanto da client web che da mobile app (nel caso avessi questa necessità in futuro).

Altrimenti, ASP.NET SignalR funzionerà lo stesso ma con trasporti meno efficienti, tipo il long polling basato su normali richieste ajax.


a questione se usare un SQL o meno sta nella problematica delle risorse, siccome ha bisogno di una continua chiamata.

Uhm, non ho ben capito lo scenario. Se devi realizzare una chat puoi certamente usare Sql Server per memorizzare i messaggi: quando il tuo Hub di ASP.NET SignalR riceve un messaggio, salvalo nel db e poi invialo a tutti gli altri client.

ciao,
Moreno
Modificato da BrightSoul il 10 gennaio 2018 23.28 -

Enjoy learning and just keep making
11 messaggi dal 23 maggio 2014

BrightSoul ha scritto:

Uhm, non ho ben capito lo scenario. Se devi realizzare una chat puoi certamente usare Sql Server per memorizzare i messaggi: quando il tuo Hub di ASP.NET SignalR riceve un messaggio, salvalo nel db e poi invialo a tutti gli altri client.




Ciao Moreno, prima di tutto grazie ancora per la risposta e si ho fatto una cosa del genere, cercando di capire tra la documentazione e gli esempi che stanno in giro (anche se sono per lo più orientati al MVC).
iL mio problema sta nel fatto che ad ogni messaggio inviato mi mantiene tutta la tabella precedente e riportando dinuovo il tutto nel front (mentre nel DB il msg è singolo).

Per capire nella "chat" avviene questo

invio msg:
1

invio 2 msg:
1
1
2

ecc....


ora ti posto un elenco dei file che tengo.

NEL MIO WEBFORM
    <script type="text/javascript">

        $(function () {

            // Proxy created on the fly
            var job = $.connection.chatHub;

            // Declare a function on the job hub so the server can invoke it
            job.client.displayStatus = function () {
                getData();
            };

            // Start the connection
            $.connection.hub.start({ transport: 'longPolling' } );
            getData();
        });

        function getData() {
            var $tbl = $('#tbl');

            $.ajax({
                url: 'Chat.aspx/GetData',
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                type: "POST",
                success: function (data) {
                    //debugger;
                    if (data.d.length > 0) {

                        newdata = data.d;
                        $tbl.empty();

                        var rows = [];

                        for (var i = 0; i < newdata.length; i++) {
                            
                                rows.push(' <tr><td>' + newdata[i].Id + '</td><td>' + newdata[i].Username + 
                                
                                $tbl.append(rows.join(''));
                        }
                    } 
                }   
             });
        }

    </script>


NEL CODEBEHIND DELLA WEB FORM ( messaggi è una classe con delle proprietà)

    <WebMethod>
    Public Shared Function GetData() As List(Of messaggi)

        Using connection = New SqlConnection(ConfigurationManager.ConnectionStrings("DatabaseSQL").ConnectionString)
            connection.Open()
            Dim lstRecords = New List(Of messaggi)()
            lstRecords.Clear()

            Using command As SqlCommand = New SqlCommand("select id, username, messaggio, tipomessaggio,inviaa from chat_1", connection)

                command.Notification = Nothing

                Dim dependency As SqlDependency = New SqlDependency(command)
                AddHandler dependency.OnChange, AddressOf Dependency_OnChange ' += new onchangeeventhandler(dependency_onchange)

                If connection.State = ConnectionState.Closed Then connection.Open()
                Using reader = command.ExecuteReader()
                    'lstRecords.ingresso =
                    lstRecords = reader.Cast(Of IDataRecord)().[Select](Function(x) New messaggi() With {.Id = x.GetInt32(0), .Username = x.GetString(1), .Messaggio = x.GetString(2), .TipoMessaggio = x.GetInt32(3), .InviaA = x.GetString(4)}).ToList()
                    Return lstRecords
                End Using
            End Using
        End Using

    End Function

    Private Shared Sub Dependency_OnChange(ByVal sender As Object, ByVal e As SqlNotificationEventArgs)
        'If (e.Type = SqlNotificationType.Change) Then
        ChatHub.Show()
        'End If
    End Sub

    Private Sub BtnInvia_Click(sender As Object, e As EventArgs) Handles BtnInvia.Click
        Dim client = New Net.WebClient()
        client.Headers.Add("apikey", ConfigurationManager.AppSettings("apikey"))
        Dim data = New NameValueCollection()
        Dim username As String = String.Empty
        If (Request.Cookies("UserSettings") IsNot Nothing) Then
            username = Request.Cookies("UserSettings")("Username")
        End If
        Dim InviaA As String = 0
        Dim TipoMessaggio As Integer = 1
        Dim testo As String = TxtMessaggio.Text

        ''SUSSURRO''
        Dim controlloStringa As Boolean = testo.Contains("@")
        If controlloStringa AndAlso (testo.IndexOf("@") = 0) Then
            Dim sussurro As String() = Split(testo, "@")
            If sussurro.Length = 3 Then
                InviaA = sussurro(1)
                testo = sussurro(2)
                TipoMessaggio = 2
            End If
        End If

        With data
            .Add("Username", username)
            .Add("Messaggio", testo)
            .Add("TipoMessaggio", TipoMessaggio)
            .Add("InviaA", InviaA)
        End With

        Dim result = client.UploadValues(ConfigurationManager.AppSettings("EndPointUrl") & "Chat/Inserisci", data)
        'Dim ObjectResult As ServicesResult.ObjectResult = Newtonsoft.Json.JsonConvert.DeserializeObject(Of ServicesResult.ObjectResult)(Encoding.ASCII.GetString(result))
        'If Not ObjectResult.ErrorResult Then
        '    Dim _result As List(Of Models.Missiva) = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of Models.Missiva))(ObjectResult.ValueResult.ToString)

        '    listaMissive.DataSource = _result
        '    listaMissive.DataBind()
        'Else
        '    Response.Write(ObjectResult.ErrorMessage)
        'End If
        TxtMessaggio.Text = ""
        TxtMessaggio.Focus()
    End Sub


NEL MIO HUB


<HubName("chatHub")>
Public Class ChatHub
    Inherits Hub

    Public Shared Sub Show()
        Dim context As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of ChatHub)()

        context.Clients.All.DisplayStatus()
    End Sub
End Class

11 messaggi dal 23 maggio 2014
Perfetto ho trovato anche l'errore che sta nel ciclo for lato client, andando ad immagazzinare anche le informazioni precedenti, anche se dichiarandone uno nuovo doveva rendermelo pulito. ad ogni modo ho utilizzato un ciclo foreach sull'oggetto data ed ora viene visualizzato bene.

ultimo problema che non riesco a risolvere lato server sarebbe questo:
Private Shared Sub Dependency_OnChange(ByVal sender As Object, ByVal e As SqlNotificationEventArgs)
        'If (e.Type = SqlNotificationType.Change) Then
        ChatHub.Show()
        'End If
    End Sub


praticamente ho commentato l'if altrimenti non andava, siccome volevo far si che la funzione dell'hub fosse richiamata solamente in caso di modifica con SqlNotificationType.Change, ma questo mi restituisce sempre 0, mentre e.Type mi restituisce 1. non riesco a venirne a capo qualche idea?
Modificato da Cicico il 13 gennaio 2018 16.48 -
10.326 messaggi dal 09 febbraio 2002
Contributi
Ciao,
perché hai bisogno delle SqlNotification?
Non puoi semplicemente inoltrare il messaggio agli altri client connessi subito dopo aver persistito il messaggio nel database?

Guarda come ha fatto Marco in questo script:
http://www.aspitalia.com/script/1122/Inviare-Messaggi-Client-Real-Time-Tramite-Hub-ASP.NET-SignalR.aspx

Ecco l'esempio applicato al tuo caso:
public void SendMessage(string message)
{
  //Qui salvi il messaggio in SQL Server

  //e poi lo giri a tutti gli altri client
  this.Clients.AllExcept(this.Context.ConnectionId).newMessage(message);
}


Usando Clients.AllExcept puoi mandare il messaggio a tutti i client (tranne ovviamente al mittente che l'ha inviato).

ciao,
Moreno

Enjoy learning and just keep making
11 messaggi dal 23 maggio 2014
BrightSoul ha scritto:

Ecco l'esempio applicato al tuo caso:
public void SendMessage(string message)
{
  //Qui salvi il messaggio in SQL Server

  //e poi lo giri a tutti gli altri client
  this.Clients.AllExcept(this.Context.ConnectionId).newMessage(message);
}


Usando Clients.AllExcept puoi mandare il messaggio a tutti i client (tranne ovviamente al mittente che l'ha inviato).

ciao,
Moreno


Se guardi nel mio script io faccio sempre richiamo a GetData, quindi volevo fare in modo che la mia funzione Show() dell'hub fosse richiamata solo quando il database avrà notificato una modifica. Però effettivamente così vado a chiamare sempre la funzione Select, quindi una nuova query ad ogni invio.

Inoltre nella mia Chat non sono previste solo semplici scritte (es. nomeUtente: messaggio), ma potrebbero variare in base al comando dato che poi gestisco con il campo TipoMessaggio.

Con l'esempio sopra citato posso far visualizzare anche i messaggi modificati (magari in base proprio al campo TipoMessaggio dove vado ad inserire io che tipo sarebbe), quindi magari un cambio di colore alla scritta del messaggio o formattazione html differente?

Quindi riprendendo il mio esempio di sopra dove nel front ho inserito questa riga di codice

job.client.displayStatus = function () {
                getData();
                $('#BtnInvia').attr("disabled", false);
            };


invece di utilizzare displayStatus vado ad utilizzare newMessage per creare la formattazione che voglio?
Questa domanda te la pongo perchè anche vedendo l'esempio lui fa un richiamo nello script a server.newMessage, in questo caso perchè viene aggiunto server? siccome io nel mio esempio non l'ho inserito, però funziona lo stesso, inoltre posso gestire più Chat con lo stesso hub chiamandolo con funzioni differenti o magari conviene utilizzare la funzione Group?

Poi inviando tutti questi messaggi sul server c'è qualche problema di memoria oppure siccome uso l'SQL non ho problemi?

ciao,
Ciro
Modificato da Cicico il 15 gennaio 2018 14.05 -
Modificato da Cicico il 15 gennaio 2018 14.17 -
10.326 messaggi dal 09 febbraio 2002
Contributi
Ciao Ciro,

Poi inviando tutti questi messaggi sul server c'è qualche problema di memoria

io penso di sì, perché vedo che crei sempre delle nuove SqlDependency ma non invochi mai il metodo Stop per arrestarle.

Come torno a ripetere, secondo me le SqlDependency non sono necessarie. Però scusami perché io non ho ancora capito qual è il tuo scenario. Ho visto del codice però non hai spiegato quale problema devi risolvere o cosa devi realizzare.

Si tratta di una comune chat con varie stanze? Oppure hai dei record in anagrafica e vuoi che i client siano notificati quando si verificano cambiamenti su quei record?

In entrambi i casi, puoi aggiungere il client ad un Group di SignalR. Questo group avrà il nome della risorsa che il client deve monitorare. Se si tratta della stanza di una chat, chiamerai il gruppo "Stanza1" dove 1 è l'id della stanza.
Se il client deve monitorare un record in anagrafica (ad esempio: un record della tabella Customer) chiamerai il gruppo "Customer1", dove 1 è l'id del Customer.

Poi, quando qualcuno usa la tua applicazione per inviare un messaggio nella stanza o per cambiare l'anagrafica del Customer, invoca una funzione client per il gruppo che porta il relativo nome e come parametri passagli un oggetto che descriva il cambiamento apportato (se è una chat, sarà un messaggio, se è un Customer, sarà il valore aggiornato).
http://www.aspitalia.com/script/1123/Gestire-Gruppi-Hub-ASP.NET-SignalR.aspx

ciao,
Moreno

Enjoy learning and just keep making
11 messaggi dal 23 maggio 2014
ciao Moreno grazie per la risposta, come prima cosa la SqlDependency sia lo Start che lo Stop li avevo posizionati nel Global.asax all'avvio e uscita dell'applicazione. 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, quindi volevo solamente capire se invocare solo all'inizio la chiamata sql della chat, quindi rimuovendo come mi hai fatto notare tu l'sqlDependency e dopo innestare il nuovo messaggio tramite la chiamata all'Hub attraverso un metodo come nel mio esempio uso displayStatus.

Ora come cosa vorrei capire se devo creare una chiamata all'hub unica per tutte le chat ( che in questo caso è displayStatus ) o se facendo in questo modo ad ogni nuovo messaggio vado ad innestare questo nuovo messaggio a tutte le chat, quindi devo creare funzioni differenti per ogni Chat utilizzata.

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 per ricaricare la select che faccio all'apertura della pagina svuotando così la memoria del server o fare altro se è possibile.
Modificato da Cicico il 17 gennaio 2018 20.34 -

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.