27 messaggi dal 07 luglio 2008
Ciao a tutti.

Vorrei sottoporvi un (credo) semplice quesito.

Ho questa classe:

Public Class cGenerale
Inherits System.Web.UI.Page
Public Property IDFrn As Integer

Function DatiFornitore() As MySqlDataReader
Dim conn As New MySqlConnection("Data Source=localhost;Database=mydb; User ID=root; password=mypwd;")
Dim MySql As String = "SELECT * FROM fornitori WHERE id = " & IDFrn
Dim myCommand As New MySqlCommand(MySql)
myCommand.Connection = conn
conn.Open()
Return myCommand.ExecuteReader()
conn.Close()
DatiFornitore.Close()
myCommand.Connection.Close()
myCommand.Dispose()

End Function
End Class

Nella pagina aspx ho questo codice:

<form id="form1" runat="server">
<% Session("conta") = Session("conta") + 1
Dim _dati = New cGenerale()
_dati.IDFrn = 1
Dim Datifrn = _dati.DatiFornitore()
While Datifrn.Read
ragsoc.Text = (Datifrn(1))
indir.Text = (Datifrn(2))
city.Text = (Datifrn(3))
prov.Text = (Datifrn(4))
End While

_dati.Dispose()
Datifrn.Close()
conta.Text = Session("conta")
%>
<div>
<p>Dati del fornitore</p>
<asp:TextBox ID="conta" runat="server"></asp:TextBox>
<asp:TextBox ID="ragsoc" runat="server"></asp:TextBox>
<asp:TextBox ID="indir" runat="server"></asp:TextBox>
<asp:TextBox ID="city" runat="server"></asp:TextBox>
<asp:TextBox ID="prov" runat="server"></asp:TextBox>
</div>
</form>

Tutto funziona e i dati vengono visualizzati correttamente nelle textbox ma dopo 129 pressioni (uso session("conta") come contatore) del tasto F5 (refresh) ottengo questo errore:

Too many connections

Descrizione: Eccezione non gestita durante l'esecuzione della richiesta Web corrente. Per ulteriori informazioni sull'errore e sul suo punto di origine nel codice, vedere la traccia dello stack.

Dettagli eccezione: MySql.Data.MySqlClient.MySqlException: Too many connections

Errore nel codice sorgente:


Riga 14: Dim myCommand As New MySqlCommand(MySql)
Riga 15: myCommand.Connection = conn
Riga 16: conn.Open()
Riga 17: Return myCommand.ExecuteReader()
Riga 18: conn.Close()

File di origine: C:\inetpub\wwwroot\test\cGenerale.vb Riga: 16

Dopo questo errore devo fare un riciclo dell'application pool associata all'applicazione e tutto ritorna a funzionare correttamente per le successive 129 pressioni e poi l'errore si ripresenta puntuale come un orologio svizzero.

Come potete vedere ho messo dispose e close un po ovunque per essere sicuro di chiudere le connessioni ma non serve a nulla il problema si ripresenta dopo 129 refresh della pagina indipendentemente dalla frequenza del refresh (tasto F5 premuto continuamente o a intervalli...).

in questo esempio uso MySql ma si presenta anche con SqlServer 2008 r2 express.

Utilizzo Windows server 2008 R2 con IIS 7.5 e per l'applicazione utilizzo l'app.pool di default V4.0 fornita da IIS 7.5 senza alcuna modifica.

Qualcuno sa come si risolve questo problema?
Si tratta di un problema della logica che uso?

Grazie per qualsiasi aiuto.
175 messaggi dal 02 gennaio 2012
Dopo
conn.Close()

aggiungi
conn.Dispose() perche' solo in quel momento avviene la liberazione (richiamo del garbage collector) delle risorse allocate.

by ghg
27 messaggi dal 07 luglio 2008
Grazie mille per la risposta. Ho fatto come mi hai suggerito ma adesso dopo 135 refresh (indipendentemente dall'intrvallo di tempo) ottengo questo messaggio:

error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
Descrizione: Eccezione non gestita durante l'esecuzione della richiesta Web corrente. Per ulteriori informazioni sull'errore e sul suo punto di origine nel codice, vedere la traccia dello stack.

Dettagli eccezione: MySql.Data.MySqlClient.MySqlException: error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.

Errore nel codice sorgente:

Riga 14: Dim myCommand As New MySqlCommand(MySql)
Riga 15: myCommand.Connection = conn
Riga 16: conn.Open()
Riga 17: Return myCommand.ExecuteReader()

File di origine: C:\inetpub\wwwroot\test\cGenerale.vb Riga: 16

Come nel post precedente devo eseguire un riciclo dell'application pool associata all'applicazione.

So che aumentando maxpoolsize nella stringa di connessione il problema si risolve (a dire il vero non si risolve, il problema si ripresenta dopo un numero maggiore di refresh), quello che vorrei conoscere da voi esperti è cosa causa questo errore?

In particolare:

"This may have occurred because all pooled connections were in use"

"In use" da chi o da cosa se le connessioni vengono eliminate dal garbage collector con l'istruzione "Dispose"?

E poi:

"and max pool size was reached"

Che cosa "rimane" e concorre a far raggiungere e superare la capacità massima?

Scusate se le domande vi sembrano banali ma per mè è importante conoscere le cause di un problema perchè solo così si possano trovare le soluzioni migliori.

Grazie a tutti per qualsiasi aiuto.
27 messaggi dal 07 luglio 2008
Ho trovato la soluzione!!!!

In Function DatiFornitore() tutte le istruzioni dopo "Return...." sono inutili perchè vengono ignorate infatti dopo return il controllo torna al chiamante.

Pertanto le istruzioni close e dispose devono essere messe nel codice dopo che il controllo è tornato al chiamante OVVIO!!!

Mica tanto ovvio perchè se guardate il codice che ho postato all'inizio troverete che le istruzioni close e dispose erano comunque presenti anche dopo che il codice aveva ripreso il controllo .....

E Allora dov'era il problema?

Semplice (adesso che l'ho capito) il Garbage Collector non faceva attempo a "Passare" e ripulire prima che l'application pool si "riempisse" pertanto è stato sufficente "invitarlo" a fare il suo dovere con un GC.Collect()

Pertanto il codice giusto è

Public Class cGenerale
 Inherits System.Web.UI.Page
 Public Property IDFrn As Integer

 Function DatiFornitore() As MySqlDataReader
 Dim conn As New MySqlConnection("Data Source=localhost;Database=mydb; User ID=root; password=mypwd;")
 Dim MySql As String = "SELECT * FROM fornitori WHERE id = " & IDFrn
 Dim myCommand As New MySqlCommand(MySql)
 myCommand.Connection = conn
 conn.Open()
 Return myCommand.ExecuteReader()
  End Function
End Class


e nella pagina aspx:

<form id="form1" runat="server">
 <% Session("conta") = Session("conta") + 1 
Dim _dati = New cGenerale()
 _dati.IDFrn = 1
 Dim Datifrn = _dati.DatiFornitore()
 While Datifrn.Read
 ragsoc.Text = (Datifrn(1))
 indir.Text = (Datifrn(2))
 city.Text = (Datifrn(3))
 prov.Text = (Datifrn(4))
 End While
 
_dati.Dispose()
 Datifrn.Dispose()
 <b>GC.Collect</b>
 conta.Text = Session("conta")
 %>
 <div>
 <p>Dati del fornitore</p>
 <asp:TextBox ID="conta" runat="server"></asp:TextBox>
 <asp:TextBox ID="ragsoc" runat="server"></asp:TextBox>
 <asp:TextBox ID="indir" runat="server"></asp:TextBox>
 <asp:TextBox ID="city" runat="server"></asp:TextBox>
 <asp:TextBox ID="prov" runat="server"></asp:TextBox>
 </div>
 </form>



Spero che questo possa essere utile a qualcun'altro.

Ciao a tutti.

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.