2009-01-12 6 views
11

Ich habe eine Assembly, die mehrere WCF-Dienste enthält, jeder mit einem eigenen Vertrag. Alles funktioniert gut. Die Dienstkonfiguration in der app.config für den Dienst sieht wie folgt aus:Können mehrere WCF-Dienste eine gemeinsame BaseAddress teilen?

<services> 
    <service behaviorConfiguration="WcfService.AlyzaServiceBehavior" 
    name="Sam.Alyza.WcfService.ServiceWebsites"> 
    <endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites"> 
     <identity> 
     <dns value="localhost" /> 
     </identity> 
    </endpoint> 
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/Websites/" /> 
     </baseAddresses> 
    </host> 
    </service> 
    <service behaviorConfiguration="Sam.Alyza.WcfService.LogReaderServiceBehavior" 
    name="Sam.Alyza.WcfService.ServiceLogReader"> 
    <endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader"> 
     <identity> 
     <dns value="localhost" /> 
     </identity> 
    </endpoint> 
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/LogReader/" /> 
     </baseAddresses> 
    </host> 
    </service> 
    <service behaviorConfiguration="Sam.Alyza.WcfService.ServiceSystemverwaltungBehavior" 
    name="Sam.Alyza.WcfService.ServiceSystemverwaltung"> 
    <endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung"> 
     <identity> 
     <dns value="localhost" /> 
     </identity> 
    </endpoint> 
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/Systemverwaltung/" /> 
     </baseAddresses> 
    </host> 
    </service> 
    [...] 
</services> 

Da ich ein größeres Projekt im Sinn haben, mit mehr Verträge, ich möchte einen Weg haben, um die Baseaddress zu teilen zwischen die verschiedenen Serviceverträge.
Wenn dies nur ein Dienst mit verschiedenen Verträgen und Endpunkten wäre, könnte ich eine allgemeine Basisadresse festlegen, aber wie lege ich eine gemeinsame Basisadresse für mehrere Dienste fest?

Natürlich würde ich etwas ähnliches für den Kunden brauchen.

Antwort

8

Sie können alle Verträge in einer Klasse kombinieren, sodass Sie einen Dienst mit einer Basisadresse und einem (oder mehreren) Endpunkt (en) pro Vertrag haben.

Um zu vermeiden, dass Sie eine große Klassendatei haben, können Sie das Partial-Schlüsselwort verwenden (unter der Annahme, dass Sie C# verwenden), um die Klasse auf mehrere Dateien aufzuteilen. Jede Datei kann einen Vertrag implementieren, was die Pflege der einzelnen Schnittstellen erheblich erleichtert.

in C++ Sie #includes oder Mehrfachvererbung verwenden können, aber dass eine große Menge an Disziplin bedeuten ...

Ihre Config würde wie folgt aussehen:

<services> 
    <service behaviorConfiguration="WcfService.AlyzaServiceBehavior" 
    name="Sam.Alyza.WcfService.ServiceAll"> 
    <endpoint address="Websites/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites"> 
     <identity> 
     <dns value="localhost" /> 
     </identity> 
    </endpoint> 
    <endpoint address="LogReader/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader"> 
     <identity> 
     <dns value="localhost" /> 
     </identity> 
    </endpoint> 
    <endpoint address="Systemverwaltung/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung"> 
     <identity> 
     <dns value="localhost" /> 
     </identity> 
    </endpoint> 
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/" /> 
     </baseAddresses> 
    </host> 
    </service> 
</services> 
+0

Schöne Idee! Das einzige Problem ist: Die partielle ServiceAll-Klasse wird groß sein, mit vielen und vielen Methoden. – Sam

+0

Das stimmt. Im Moment sehe ich keine andere Lösung, als auf Code-basierte Instanziierung umzusteigen. – Lars

2

Dienste können BaseAddress-Werte teilen (einschließlich Port-Nummern, wenn der Net.Tcp-Portfreigabedienst ausgeführt wird). Es sind die Endpunktadressen, die eindeutig sein müssen. Beachten Sie in Ihrer Konfigurationsdatei, dass die MEX-Endpunkte für jeden ServiceHost die Adresse "mex" haben. Ihre anderen Endpunkte haben eine Adresse mit einer leeren Zeichenfolge. Wenn Sie WCF eine relative Adresse für einen Endpunkt angeben (zumindest in der Konfigurationsdatei), wird die Basisadresse diesem Endpunkt vorangestellt. Daher lautet die MEX-Endpunktadresse für den LogReader-Dienst "net.tcp: // localhost: 8731/Design_Time_Addresses/SamAlyza/LogReader/mex".

Da für den Haupt-Serviceendpunkt keine relative Adresse festgelegt wurde, wird die Basisadresse des ServiceHost als tatsächliche Adresse für den Haupt-Serviceendpunkt verwendet. Da zwei Endpunkte keine überlappenden Uri.AbsolutePath-Werte haben können, führt Ihr Beispiel zu der Annahme, dass die Basisadresswerte nicht gemeinsam genutzt werden können. Die ServiceHost-Klasse, die WCF-Dienste hostet, verfügt nicht über einen integrierten Endpunkt, während die ServiceEndpoint-Klasse über eine ListenUri-Eigenschaft verfügt, die basierend auf den von Ihnen bereitgestellten Einstellungen ausgefüllt wird.

Wenn Sie die baseAddress-Werte in Ihrem Beispiel auf "alle übereinstimmen" setzen, solange Sie eindeutige relative Adresswerte für die Endpoint-Elemente festlegen, sollte alles funktionieren. Es sieht jedoch so aus, als könnten Sie mit den MEX-Endpunkten einige Probleme haben, da sie alle die Adresse "mex" haben. Machen Sie diese einzigartig und Sie sollten in Ordnung sein.

Jetzt muss ich fragen, sind Sie sicher, dass Sie nicht einfach wollen, dass diese Dienste einen Namespace teilen, anstatt Basisadressen?

+0

Ein weiterer Punkt wäre, dass eine baseAddress nicht mehr als der aktuelle Speicherort ist, sozusagen. Die Idee ist, dass alle Endpunkte im Allgemeinen relativ zu der baseAddress sind. Wenn Sie versuchen, die gleiche baseAddress für alle Services zu verwenden, beschränken Sie daher Ihre Bereitstellungsoptionen. –

+0

Wenn Sie nach einer Möglichkeit suchen, die Konfiguration zu vereinfachen, müssen Sie statt der Konfigurationsverkabelung Code verwenden. Sie könnten die ServiceHost- und ServiceEndpoint-Instanzen programmgesteuert erstellen und möglicherweise Uri.AbsolutPath-Werte aus einer Datenbank abrufen. –

+0

Ja, ich suche nach einer Möglichkeit, die Konfigurationsdatei einfacher zu ändern. Also, wenn Sie irgendwelche Ideen dazu haben, wäre ich ganz Ohr. – Sam

1

Sie auch die Basis einstellen Adressen in Code, wenn Sie eine benutzerdefinierte ServiceHostFactory verwenden.

In Config können Sie einige App-Einstellung haben:

<configuration> 
    <appSettings> 
    <add key="BaseAddress" value="http://localhost:1234" /> 
    </appSettings> 
<configuration> 

Dann eine eigene Servicehost machen:

public sealed class MyServiceHostFactory : ServiceHostFactory 
{ 
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
    { 
     var baseAddy = ConfigurationManager.AppSettings["BaseAddress"]; 
     baseAddresses.Add(new Uri(baseAddy)); 
     return new ServiceHost(serviceType, baseAddresses); 
    } 

} 

dann diese Fabrik zu verwenden, müssen Sie auch Ihre .svc Dateien ändern:

<%@ ServiceHost Language="C#" Debug="true" Service="MyApp.MyService" CodeBehind="MyService.svc.cs" Factory="MyApp.MyServiceHostFactory" %> 
Verwandte Themen