2014-06-23 11 views
5

Ho un'applicazione basata su un servizio Duplex WCF. Ho problemi quando l'utente "riavvia" il lavoro che l'applicazione fa ... sotto il cofano, il lato client chiude la connessione al servizio WCF e ne crea un altro. Il contratto di servizio è definita in questo modo ...WCF Duplex Service Channel Close

[ServiceContract(Namespace="net.tcp://namespace.MyService", 
    SessionMode=SessionMode.Required, 
    CallbackContract=typeof(IServiceCallback))] 
public interface IMyService 
{ 
    [OperationContract(IsOneWay=true)] 
    void DoWork(); 
} 


public interface IServiceCallback 
{ 
    [OperationContract(IsOneWay=true)] 
    void SendMessage(string message); 
} 

L'implementazione è definito come:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, 
    InstanceContextMode = InstanceContextMode.PerSession, 
    UseSynchronizationContext = false, 
    IncludeExceptionDetailInFaults = true)] 
public class MyService : IMyService 
{ 
    public void DoWork() 
    { 
     var callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>(); 
     callback.SendMessage("Hello, world."); 
    } 
} 

La configurazione per il client è la seguente:

<system.serviceModel> 
    <bindings> 
     <netTcpBinding> 
     <binding name="net.tcp" receiveTimeout="02:00:00" sendTimeout="02:00:00" maxReceivedMessageSize="2147483647"> 
      <security mode="None"/> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <client> 
     <endpoint address="net.tcp://localhost:8000/MyService/MyService" 
      binding="netTcpBinding" bindingConfiguration="net.tcp" contract="ExternalServiceReference.IMyService"> 
     </endpoint> 
    </client> 
    </system.serviceModel> 

Config per il servizio :

<system.serviceModel> 
<behaviors> 
    <serviceBehaviors> 
    <behavior name="serviceBehaviour"> 
     <serviceMetadata /> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 
<bindings> 
    <netTcpBinding> 
    <binding name="netTcp" sendTimeout="01:00:00" receiveTimeout="01:00:00" > 
     <security mode="None"> 
     </security> 
    </binding> 
    </netTcpBinding> 
</bindings> 
<services> 
    <service behaviorConfiguration="serviceBehaviour" name="MyService.MyService"> 
    <endpoint address="MyService" binding="netTcpBinding" bindingConfiguration="netTcp" name="net.tcp" contract="MyService.IMyService" /> 
    <endpoint binding="mexTcpBinding" bindingConfiguration="" name="net.tcp" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:8000/MyService" /> 
     </baseAddresses> 
    </host> 
    </service> 
</services> 

Nel contructor del cliente:

var callback = new CallbackImplementation(); 
_context = new InstanceContext(callback); 
_proxy = new MyServiceProxy(_context); 

sto cercando il seguente prima di stabilire una nuova connessione:

 try 
     { 
      if (_context != null) 
      { 
       _context.ReleaseServiceInstance(); 
       _context.Close();      
      } 
     } 
     catch (Exception ex) 
     { 
      Debug.WriteLine(ex.Message); 
      if (_context != null) 
      { 
       _context.Abort(); 
      } 
     } 

Il problema che vedo è che la chiamata _context.Close() scade sempre e genera un'eccezione. Anche se interrompo il canale, questo mi sembra sbagliato, e credo che sia la causa del congelamento nella mia applicazione. Qualcuno sa perché la chiamata a Close() fallisce?

MODIFICA: Ho perso qualcosa in precedenza per quanto riguarda la mia implementazione di callback che potrebbe essere rilevante. Sembra qualcosa di simile a questo:..

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Single, 
    UseSynchronizationContext = false, 
    IncludeExceptionDetailInFaults = true)] 
public class CallbackImplementation : IServiceCallback 
{ 
    public void SendMessage(string message) 
    { 
     // Do something with the message 
    } 
} 

Il messaggio di eccezione è "Il ServiceHost operazione di chiusura scaduta dopo 0:00:30 Questo potrebbe essere perché un cliente non è riuscito a chiudere un canale con sessione entro il tempo richiesto Il tempo assegnato a questa operazione potrebbe essere stata una parte di un timeout più lungo. ". Non c'è eccezione interiore.

Grazie

+0

Prova ad aggiungere un gestore di eventi 'OnClose'. Verifica se l'evento viene attivato sul lato server 'callback'. – mrtig

+0

Grazie, l'ho appena provato: gli eventi di chiusura e chiusura stanno sparando. – MrShoes

+0

Ma il servizio sta ancora scadendo? Hai provato a impostare 'CloseTimeout' sull'associazione? – mrtig

risposta

0

il problema è stato non solo la concorrenza, ma il tipo di rilegatura.

Assicurarsi che la modalità di concorrenza sia del servizio sia della richiamata fosse un passo nella giusta direzione. Ma cambiare l'associazione da netTcpBinding a wsDualHttpBinding ha finalmente risolto il problema

0

Hai provato ReceiveTimeout = "infinito", per vedere se si continua a ricevere l'errore. Potresti solo scoprire che non è il timeout a creare l'errore. Hai pensato di creare una classe client di base che mantenga automaticamente attive le connessioni fino alla chiusura fisica?

1

Non vedo subito un problema, ma spesso trovo che le tracce in esecuzione sul client e sul server e l'esame dei risultati di solito mi indicano la soluzione. Metti questo nei tuoi file .config (client e server), assicurati che il percorso rimandi a una cartella esistente. Esegui la tua app, ottieni l'errore, quindi chiudi tutto ed esegui SvcTraceViewer.exe per leggere i risultati.

<system.diagnostics> 
    <sources> 
     <source name="System.ServiceModel" switchValue="Information,ActivityTracing" 
     propagateActivity="true"> 
     <listeners> 
      <add name="xml" /> 
     </listeners> 
     </source> 
     <source name="System.ServiceModel.MessageLogging"> 
     <listeners> 
      <add name="xml" /> 
     </listeners> 
     </source> 
    </sources> 
    <sharedListeners> 
     <add initializeData="C:\logs\TracingAndLogging-service.svclog" type="System.Diagnostics.XmlWriterTraceListener" 
     name="xml" /> 
    </sharedListeners> 
    <trace autoflush="true" /> 
</system.diagnostics> 
0

A occhio e croce, potrebbe essere una situazione di stallo causata dall'uso di ConcurrencyMode.Single.

Ciò che potrebbe accadere è che il server sta tentando di richiamare il client mentre sta ancora elaborando la richiesta originale (o viceversa). Quindi il server sta tentando di richiamare il client, ma il client sta bloccando perché è ancora in attesa di una risposta dal server. Ehi presto, deadlock e alla fine un timeout.

http://msdn.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx

Problemi correlati