2009-01-12 8 views
11

Tengo un conjunto que contiene varios servicios de WCF, cada uno con su propio contrato. Todo funciona bien. La configuración de servicio en el app.config para el servicio se ve así:¿Pueden varios servicios WCF compartir una BaseAddress común?

<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> 

Desde Tengo un proyecto más grande en mente, con más contratos, me gustaría tener una manera de compartir la BaseAddress entre los diferentes contratos de servicio.
Si esto solo fuera un servicio con diferentes contratos y puntos finales, podría establecer una dirección base ommon, pero ¿cómo configuro una baseaddress común para más de un servicio?

Por supuesto que necesitaría algo similar para el cliente.

Respuesta

8

Puede combinar todos los contratos en una clase, por lo que tiene un servicio con una dirección base y uno (o más) puntos finales por contrato.

Para evitar tener un gran archivo de clase, puede usar la palabra clave parcial (asumiendo que usa C#) para dividir la clase en varios archivos. Cada archivo puede implementar un contrato, lo que hace que el mantenimiento de las interfaces individuales sea mucho más fácil.

En C++ se puede utilizar #includes o herencia múltiple, pero eso implicaría una gran cantidad de disciplina ...

Su configuración se vería así:

<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

¡Buena idea! El único problema es que la clase parcial de ServiceAll será grande, con muchos métodos. – Sam

+0

Eso es correcto. Por el momento, no veo otra solución que cambiar a instanciación basada en código. – Lars

2

Los servicios pueden compartir los valores BaseAddress (incluidos los puertos #, si el servicio Net.Tcp Port Sharing se está ejecutando). Son las direcciones de punto final las que deben ser únicas. Observe en su archivo de configuración que los puntos finales MEX para cada ServiceHost tienen una dirección de "mex". Sus otros puntos finales tienen una dirección de cadena vacía. Cuando proporciona una dirección relativa para un punto final a WCF (al menos en el archivo de configuración), la dirección base se antepone a ella. Por lo tanto, la dirección del punto final MEX para el servicio LogReader es "net.tcp: // localhost: 8731/Design_Time_Addresses/SamAlyza/LogReader/mex".

Dado que no se estableció una dirección relativa en el punto final del servicio principal, la dirección base del ServiceHost se utiliza como la dirección real para el punto final del servicio principal. Dado que no hay dos puntos finales que puedan superponerse a los valores de Uri.AbsolutePath, su ejemplo lo llevará a creer que los valores de la dirección base no se pueden compartir. La clase ServiceHost que aloja servicios WCF no tiene un punto final integrado, mientras que la clase ServiceEndpoint tiene una propiedad ListenUri que se completará en función de la configuración que proporcione.

Si cambia los valores de baseAddress en su ejemplo para todas las coincidencias, siempre que establezca valores de dirección relativos únicos en los elementos del punto final, todo debería funcionar. Sin embargo, parece que puede encontrarse con algunos desafíos con los puntos finales MEX, ya que todos ellos tienen la dirección "mex" actualmente. Hazlos únicos y deberías estar bien.

Ahora, debo preguntar, ¿está seguro de que no solo quiere que estos servicios compartan un espacio de nombres, en lugar de direcciones base?

+0

Otro punto sería que una baseAddress no es más que la ubicación actual, por así decirlo. La idea es que todos los puntos finales generalmente son relativos a baseAddress. Por lo tanto, si intenta compartir la misma baseAddress en todos los servicios, está limitando sus opciones de implementación. –

+0

Si está buscando una forma de facilitar la configuración, deberá cambiar al uso de código en lugar del cableado de configuración. Podría crear mediante programación las instancias de ServiceHost y ServiceEndpoint y quizás extraer los valores de Uri.AbsolutPath de una base de datos. –

+0

Sí, estoy buscando una manera de hacer que el archivo de configuración sea más fácil de cambiar. Así que si tienes alguna idea sobre esto, sería todo oídos. – Sam

1

También puede establecer la base direcciones en el código si usa un ServiceHostFactory personalizado.

En config se puede tener un cierto ajuste de aplicación:

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

Luego haga una ServiceHostFactory personalizado:

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); 
    } 

} 

A continuación, también tiene que cambiar sus archivos .SVC utilizar esa fábrica:

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