Domanda

Ho un piccolo motore di hosting WCF che sto scrivendo che creerà dinamicamente ServiceHosts in base al file .config. L'idea generale è di consentirci di rimuovere i servizi esistenti, nonché di aggiungere nuovi servizi, in fase di esecuzione senza dover portare offline tutti i nostri servizi.

Ho riscontrato un test dell'unità di problema che indica che potrebbe non essere così semplice come sembra. Sembra che possa esistere un solo ServiceHost per un determinato endpoint (anche se in un singolo ServiceHost possono esistere più endpoint diversi per un servizio). Questo non è un problema normalmente, tuttavia quando un servizio deve essere riconfigurato, la disattivazione del ServiceHost originale non uccide effettivamente la registrazione per quell'indirizzo dell'endpoint. Il tentativo di creare un altro ServiceHost, per lo stesso servizio (il che significa che vengono utilizzati gli stessi endpoint) ha esito negativo con la seguente eccezione:

System.InvalidOperationException: The ChannelDispatcher at 'net.pipe://localhost/' with contract(s) '"ITestService"' is unable to open its IChannelListener. --->
System.InvalidOperationException: A registration already exists for URI 'net.pipe://localhost/'.

In realtà sto riscontrando l'errore durante il test dell'unità. I test eserciteranno un'unità, che chiude completamente ServiceHosts e il motore di hosting per quanto è umanamente possibile. Quindi crea un'altra istanza del motore di hosting, che tenta di ricreare nuovamente lo stesso ServiceHosts per un test diverso. Il secondo test rileva l'errore sopra. Immagino che mentre è stato chiamato ServiceHost.Close (), ciò non distrugge effettivamente l'host del servizio ... quindi rimane ancora in memoria. Non riesco a capire se il GC sta ripulendo i vecchi host di servizio o no ... il problema persiste senza andare via dopo che si è verificato inizialmente (come meglio sono stato in grado di determinare ... Ho aspettato circa 30 minuti finora. )

Il mio file di configurazione per system.serviceModel è il seguente:

  <system.serviceModel>
    <services>
      <service name="Campus.Core.ServiceModel.TestServiceStub">
        <endpoint          
          address="net.pipe://localhost"          
          binding="netNamedPipeBinding"           
          contract="Campus.Core.ServiceModel.ITestService"
        />
      </service>
    </services>
  </system.serviceModel>
È stato utile?

Soluzione

Per fornire una risposta a questa domanda, nel caso in cui qualcun altro abbia riscontrato il problema. In realtà ci sono state due cause a questo problema, come segue:

1) Durante il test dell'unità, se si verifica un'eccezione, di solito si romperà il codice testato prima che ServiceHost possa essere chiuso. Ciò ha lasciato ServiceHost associato a un particolare endpoint. Ciò ha causato il fallimento di TUTTI i test successivi che hanno esercitato lo stesso codice. Mentre stavo facendo BDD con SubSpec e xUnit, un singolo caso di test (preoccupazione in termini di BDD) eseguiva una singola asserzione per test e un singolo caso di test poteva comprendere fino a una dozzina o più di asserzioni.

2) Attenzione all'endpoint MEX. L'endpoint MEX può esistere una sola volta per servizio. Inizialmente, avevo creato un endpoint mex http e net.tcp. Ciò ha causato un problema, tuttavia, dal momento che la seconda istanza dell'endpoint MEX avviata ha generato un'eccezione. In generale, se si utilizza l'endpoint MEX, HTTP è il protocollo più utile da utilizzare, a meno che non vi siano problemi fisici infrastrutturali che impediscono di farlo.

In generale, la chiamata del metodo Close () su un ServiceHost lo separerà completamente, consentendo di riutilizzare qualsiasi indirizzo precedentemente associato ai suoi endpoint. A volte la chiusura può richiedere del tempo e, in rari casi, può essere generata un'eccezione. Se stai eseguendo BDD con SubSpec e stai seguendo la regola della singola asserzione per test, un'eccezione generata in un test che impedisce la chiusura di ServiceHosts farà fallire tutti i test successivi.

Altri suggerimenti

Una risposta è quella di aggiungere una Guida all'URL per l'host del servizio ogni volta che si gira uno e utilizzare un approccio di fabbrica che converte le istanze di ServiceHost e restituisce il canale sul lato client, in modo che il client sappia quale URL da utilizzare.

L'esempio InProcFactory di IDesign utilizza questo approccio, quindi potresti essere in grado di usarlo così com'è:

http://www.idesign.net/idesign/DesktopDefault aspx tabindex = 5 & amp;? tabid = 11

Nota che dovrai scaricare il sito IDesign per scaricare l'esempio e ti invieranno l'annuncio occasionale sulla formazione e simili, ma non è troppo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top