[c#]Catturare eccezzioni generate da thread.

lunedì 21 luglio 2008 - 19.53

program Profilo | Junior Member

Ciao,
Sto facendo un programmino che lancia un thread. Questo thread puo' generare un eccezione.
Se lancio la funzione normalmente e si verifica l'eccezione questa viene catturata dal try catch.
Se invece lancio la funzione in un thread il try catch non riesce a catturare nessuna eccezione e mi viene visualizzato quindi il problema su Visual Studio con la classica finestrella gialla e bianca.

Di solito il quadratino è anche unito da un filo all'istruzione che genera l'eccezione, ma quando uso il thread questa non ce, e si presenta solo il quadrato con la scritta.Questo mi fa pensare che essendo un thread vada trattato in modo diverso.........

Come dovrei fare?
Grazie.

rossimarko Profilo | Guru

Ciao,

la gestione dell'eccezione con il try-catch la fai all'interno della funzione lanciata dal thread oppure dove lanci la Thread.Start?

-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Ciao,
allora il try catch lo faccio dove lancio il thread.

Ti spiego meglio.
Devo far comunicare due applicazioni attraverso il Remoting con una connessione Singleton

Allora io vorrei lanciare un thread attraverso il quale avviene la comunicazione
Il problema è che se il server non è attivo, se lancio la funzione remota normalmente viene catturata l'eccezione.
Se invece il server non è attivo e faccio lanciare la funzione in un thread l'eccezione non viene catturata ma si presenta ugualmente.

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

L'eccezione che si presenta è :
Impossibile stabilire la connessione. Rifiuto persistente del computer di destinazione ip...
Socket Exception non è stata gestita.

Inoltre nei dettagli dell'eccezione viene scritto questo:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Come mai non mi cattura nulla con il thread?????
Grazie ancora.

rossimarko Profilo | Guru

Se vuoi intercettare l'errore lo devi fare all'interno della funzione richiamata dal thread. Se poi vuoi notificare al processo chiamante l'errore allora la cosa si fa più complicata perchè bisogna gestire un evento o una funzione di callback
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Ciao,
ho provato a mettere il try catch(Exception) nel metodo richiamato ma nulla......

Il thread che lancio è un metodo dell'oggetto remoto attraverso il quale faccio le operazioni che mi servono.

L'errore che mi viene ritornato è Socket Exception....ovvero non riesce a contattare il server............Però perchè mi viene catturato se non uso il thread????

Come posso ovviare?

Grazie.

rossimarko Profilo | Guru


>Il thread che lancio è un metodo dell'oggetto remoto attraverso
>il quale faccio le operazioni che mi servono.
>
>L'errore che mi viene ritornato è Socket Exception....ovvero
>non riesce a contattare il server............Però perchè mi viene
>catturato se non uso il thread????
>
>Come posso ovviare?
>
>Grazie.

L'eccezione può essere catturata solo all'interno del thread che sta eseguendo l'operazione. Quindi se metti il try catch dove fai il thread.start non riuscirai a catturare gli errori interni al thread lanciato.

Puoi postare la funzione che richiama il thread e quella che viene eseguita dal thread stesso? Così ci ragioniamo su..
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Ti allego un esempio di poche righe che da lo stesso problema...se mi puoi aiutare....

E' diviso in client server e usano il Remoting.
Allora il client tramite remoting accede a un oggetto su server che scrive il testo inviato.

Con il thread se il server non è attivo non cattura nulla........
Se al posto del thread chiamo la funzione normalmente invece la cattura.

Grazie ancora.

program Profilo | Junior Member

Questo è quello che viene avviato al click su client.

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Questo è il metodo che viene richiamato dal thread sul client.
Fa parte dell'oggetto remoto.
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

rossimarko Profilo | Guru

Ho guardato il codice. Ti consiglio di usare il controllo BackGroundWorker (http://msdn.microsoft.com/it-it/library/8xs8549b.aspx) per la gestione della chiamata, perchè ti semplifica molto la gestione, visto che quando si lavora con i thread non si può accedere direttamente ai controlli del form chiamante.
Se guardi gli esempi devi implementare l'evento DoWork e al termine andrai a gestire il risultato dell'operazione all'interno dell'evento RunWorkerCompleted.



-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Scusa ma non capisco molto....
Io il thread lo dovrei lanciare solo alla pressione di un pulsante....

Puoi farmi un esempio?

Grazie ancora.

rossimarko Profilo | Guru

Il backgroundworker è un componente da inserire come controllo nella form. Una volta inserito puoi agganciare l'evento DoWork e implementare la tua funzionalità. Allo stesso modo nell'evento RunWorkerCompleted puoi gestire l'applicazione una volta terminata l'esecuzione.

Per lanciare l'esecuzione basta richiamare il metodo RunWorkerAsync del componente dal tuo pulsante.

A questo indirizzo puoi trovare un esempio completo: http://msdn.microsoft.com/it-it/library/waw3xexc.aspx
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Scusa peò non capisco una cosa....
non riesco a capire a cosa mi possa servire nel mio caso........
La comunicazione deve avvenire alla pressione di un pulsante e se il server non c'e' deve comunicarmelo con una message box e fermare il thread....

Grazie ancora.

rossimarko Profilo | Guru

>Scusa peò non capisco una cosa....
>non riesco a capire a cosa mi possa servire nel mio caso........
>La comunicazione deve avvenire alla pressione di un pulsante
>e se il server non c'e' deve comunicarmelo con una message box
>e fermare il thread....
>

La gestione dei thread purtroppo non è una delle più semplici. Parti dal presupposto che ci sono dei vincoli architetturali da rispettare, non puoi ad esempio accedere ai controlli della form chiamante ma devi utilizzare dei metodi particolari (http://msdn.microsoft.com/en-us/library/ms171728.aspx) oppure devi gestire la cosa con degli eventi. Il backgroudWorker è stato creato apposta per semplificare tutta questa gestione e ti consente di farlo con due semplici eventi. Al suo interno ha inoltre la gestione delle eventuali eccezzioni.

Ti ho modificato il progetto facendo una piccola prova e a me funziona correttamente.
Dalla funzione threadwrite ho tolto tutte le messagebox.
Poi ho inserito il backgroundWorker nella form e ho modificato la chiamata passando come argomento il testo da inviare:
bgClient.RunWorkerAsync(txtbox.Text);

Successivamente nell'evento DoWork ho fatto l'invio:
private void bgClient_DoWork(object sender, DoWorkEventArgs e) { //Invia il comando this.t.threadwrite(e.Argument); }

e nel RunWorkerCompleted ho messo la gestione del risultato una volta completata l'operazione:
private void bgClient_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //Gestione operazione completata if (e.Error == null) { MessageBox.Show("Operazione completata correttamente"); } else { MessageBox.Show(String.Format("Errore durante esecuzione: {0}", e.Error.Message)); } }

PS: se per caso in debug ti da errore e si ferma nell'istruzione threadwrite è una cosa normale perchè non è stata gestita l'eccezione. Se lo fai andare avanti con F5 o se lo lanci senza debug vedrai che subito dopo va nell'evento completed e visualizza la message box.

Potrai comunque modificare il codice a tuo piacimento, ad esempio inserirendo la gestione del parametro result direttamente nel DoWork:
private void bgClient_DoWork(object sender, DoWorkEventArgs e) { try { //Invia il comando this.t.threadwrite(e.Argument); e.Result = true; } catch { e.Result = false; } }


-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Prima di tutto un grande Grazie.

Volevo capire un attimo meglio un paio di cose:

Il valore dell'attributo Error viene determinato dal compilatore in automatico se avviene un errore?

>PS: se per caso in debug ti da errore e si ferma nell'istruzione
>threadwrite è una cosa normale perchè non è stata gestita l'eccezione.
>Se lo fai andare avanti con F5 o se lo lanci senza debug vedrai
>che subito dopo va nell'evento completed e visualizza la message
>box.

Se non viene gestita l'eccezione come fa quindi a vedere che è avvenuto un imprevisto?
Se volessi gestire l'errore nello specifico come dovrei fare?

>Potrai comunque modificare il codice a tuo piacimento, ad esempio
>inserirendo la gestione del parametro result direttamente nel
>DoWork:
>private void bgClient_DoWork(object sender, DoWorkEventArgs e)
> {
> try
> {
> //Invia il comando
> this.t.threadwrite(e.Argument);
>
> e.Result = true;
> }
> catch
> {
> e.Result = false;
> }
> }
>
A cosa serve questo attributo Result? E' un attributo in piu' superfluo?
Mi fa venire in mente l'attributo Error di prima.....

Ancora Grazie.

rossimarko Profilo | Guru

>Prima di tutto un grande Grazie.
>
>Volevo capire un attimo meglio un paio di cose:
>
>Il valore dell'attributo Error viene determinato dal compilatore
>in automatico se avviene un errore?
>

Si, viene gestito in automatico. Ci troverai dentro un'eventuale eccezione non gestita.


>Se volessi gestire l'errore nello specifico come dovrei fare?
>
>A cosa serve questo attributo Result? E' un attributo in piu'
>superfluo?
>Mi fa venire in mente l'attributo Error di prima.....
>

Result è una proprietà che puoi valorizzare durante la DoWork e serve per poter gestire eventuali risultati durante l'evento completed. E' di tipo object quindi puoi inserire qualsiasi valore. Nel mio caso ho inserito un boolean per farti un esempio, ma puoi agire come meglio credi.

Per farti capire meglio ti giro un'altro esempio:

private void bgClient_DoWork(object sender, DoWorkEventArgs e) { try { //Invia il comando this.t.threadwrite(e.Argument); e.Result = true; } catch (Exception ex) { e.Result = ex; } } private void bgClient_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //Gestione operazione completata if (e.Error != null) { MessageBox.Show(String.Format("Errore durante esecuzione: {0}", e.Error.Message)); return; } if (e.Result is Exception) { Exception ex = (Exception)e.Result; MessageBox.Show(String.Format("Errore durante esecuzione: {0}", ex.Message)); return; } if (e.Result is Boolean) { bool bResult = (bool)e.Result; if (bResult) MessageBox.Show("Procedura eseguita correttamente"); } }
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

program Profilo | Junior Member

Ti Ringrazio.

Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5