2009-05-01 7 views
9

Uso WCF per un sistema server client. Quando aggiungo un riferimento di servizio a IService sul server, viene generata una classe proxy ServiceClient. Il mio codice è simile al seguente:Riutilizzare una classe client in WCF dopo l'errore

ServiceClient client = new ServiceClient(); 
try 
{ 
    client.Operation1(); 
} 
catch(Exception ex) 
{ 
    // Handle Exception 
} 
try 
{ 
    client.Operation2(); 
} 
catch(Exception ex) 
{ 
    // Handle Exception 
} 

Il problema è che se c'è un'eccezione di comunicazione nella prima chiamata, i cambiamenti di stato del client per Faulted, e non so come riaprirlo per rendere il seconda chiamata. C'è un modo per riaprirlo? o dovrei crearne uno nuovo e sostituire l'istanza (non sembra un modo elegante)?

risposta

0

Ciò è probabilmente causato da un'eccezione non gestita sul lato server. Il runtime WCF per impostazione predefinita termina l'istanza del servizio e mette il canale in stato di errore in caso di eccezione non gestita e non è più possibile comunicare su quel canale. Quindi dovrai stabilire una nuova sessione con il servizio. È necessario rilevare eccezioni sul lato server e inviare gli errori soap sollevando FaultException o definendo FaultContract. Esiste anche un comportamento del servizio returnUnknownExceptionsAsFaults che è possibile utilizzare.

16

Una volta che un oggetto ICommunicationObject (il tuo oggetto client WCF) si trova in uno stato di errore, l'unico modo per "riaprirlo" è crearne uno nuovo.

ServiceClient client = new ServiceClient(); 
try 
{ 
    client.Operation1(); 
} 
catch(Exception ex) 
{ 
    if (client.State == CommunicationState.Faulted) 
    { 
      client.Abort(); 
      client = new ServiceClient(); 
    } 
} 
try 
{ 
    client.Operation2(); 
} 
catch(Exception ex) 
{ 
    // Handle Exception 
} 
+0

Il problema è che abbiamo una funzione interna che ottiene un delegato a una funzione su un proxy di servizio e esegue ripetutamente la funzione fino a quando non viene generata alcuna eccezione di comunicazione (la nostra implementazione alla riconnessione automatica). Quindi, in questa soluzione, la funzione creerà un'istanza del proxy per ogni tentativo di esecuzione e dovrà restituire un'istanza aggiornata al chiamante, quindi non terrà un proxy chiuso ... Tipo di brutto: -/ – Andy

5

Se c'è un'eccezione comunicazione sulla prima chiamata che sta causando uno stato di errore, si deve fondamentalmente "ricreare" il proxy client WCF. Nel tuo esempio avrei probabilmente fare qualcosa di simile:

if (client.State == CommunicationState.Faulted) 
    client = new ServiceClient(); 

Questo permetterebbe di "riaprire" la connessione se è guasto. Può sembrare un po 'eccessivo, ma se stai ricevendo un'eccezione di comunicazione sul lato client, probabilmente c'è qualcos'altro (ad esempio:? Server morti server non risponde)

Buona fortuna

3

D'accordo con le ultime risposte, una volta fallite, devi abortire. Si usa una combinazione di lambda e un metodo come segue per fare questo:

public static void Use<TServiceInterface>(TServiceInterface proxy, Action handler) 
    { 
    Type proxyType = typeof(TServiceInterface); 
    IClientChannel channel = (IClientChannel)proxy; 

    try 
    { 
     handler(); 

     _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name)); 

     channel.Close(); 

     _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name)); 
    } 
    catch 
    { 
     if (channel.State == CommunicationState.Faulted) 
     { 
      _logSource.Log(LogLevel.Debug, string.Format("Aborting client channel for '{0}' ...", proxyType.Name)); 

      channel.Abort(); 

      _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' aborted.", proxyType.Name)); 
     } 
     else 
     { 
      _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name)); 

      channel.Close(); 

      _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name)); 
     } 

     throw; 
    } 
    } 

Questa è una leggera modifica di una soluzione che è già sul NET, ma funziona grande per la gestione proxy. È quindi possibile inserire più chiamate di servizio nella stessa espressione lambda e passarle nel metodo.

+1

Nella soluzione che hai fornito, chiudi sempre il canale dopo il primo utilizzo e potrebbe comportare prestazioni inadeguate o funzionalità errate durante l'uso della sessione. È anche strano che una funzione che non crea il canale, lo sta chiudendo. – Andy

+0

Il metodo sopra si comporta come un'istruzione using in C#. Sei corretto che richiama dopo che l'azione del gestore è stata eseguita, ma penso che quello che ti manca è che ci può essere un numero infinito di istruzioni nell'azione del gestore. Potresti effettuare 15 chiamate all'interfaccia di servizio, se lo desideri. Inoltre, non credo sia strano che la funzione non faccia tutto. È abbastanza comune separare la costruzione e la distruzione di un oggetto in un metodo separato o in segmenti separati di codice. Le fabbriche in genere non si assumono la responsabilità di ripulire gli oggetti che creano –