2008-12-02 16 views
49

Ejecución de una ServiceHost con un único contrato está trabajando muy bien como esto:Run WCF ServiceHost con múltiples contratos

servicehost = new ServiceHost(typeof(MyService1)); 
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1"); 
servicehost.Open(); 

Ahora me gustaría añadir un segundo contrato (días 3, 4, ...). Mi primera conjetura sería simplemente añadir más puntos finales de la siguiente manera:

servicehost = new ServiceHost(typeof(MyService1)); 
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1"); 
servicehost.AddServiceEndpoint(typeof(IMyService2), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService2"); 
servicehost.Open(); 

Pero por supuesto esto no funciona, ya que en la creación de ServiceHost cualquiera me puede pasar MyService1 como parámetro o MyService2 - por lo que puedo añadir mucho de puntos finales para mi servicio, pero todos tienen que usar el mismo contrato, ya que solo puedo proporcionar una implementación.
Tengo la sensación de que me estoy perdiendo el sentido, aquí. ¿Seguro que debe haber alguna manera de proporcionar una implementación para cada contrato final que agregue, o no?

Respuesta

56

Necesita implementar ambos servicios (interfaces) en la misma clase.

servicehost = new ServiceHost(typeof(WcfEntryPoint)); 
servicehost.Open(); 

public class WcfEntryPoint : IMyService1, IMyService2 
{ 
    #region IMyService1 
    #endregion 

    #region IMyService2 
    #endregion 
} 

FYI: Suelo utilizar las clases parciales para que mi código de clase de acogida más fácil de leer: Respuesta

// WcfEntryPoint.IMyService1.cs 
public partial class WcfEntryPoint : IMyService1 
{ 
    // IMyService1 methods 
} 

// WcfEntryPoint.IMyService2.cs 
public partial class WcfEntryPoint : IMyService2 
{ 
    // IMyService2 methods 
} 
+9

Dang.Necesito más que solo 2 contratos de servicio, supongo que 10-50, y para ese número este enfoque es un poco engorroso; no es muy útil tener todos los puntos de entrada en una sola clase :( ¿No hay otro forma? – Sam

+0

Mi solución le permite dividir los contratos en diferentes clases. También puede combinar mi solución con escalofríos para tener, por ejemplo, 5 clases, cada una con 2 puntos finales. Tengo mucha curiosidad por saber por qué necesita 50 contratos. mira las mejores prácticas de Juval en http://www.idesign.net/. –

+1

Voy a secundar el comentario de Chris. Parece que necesitas simplificar tu diseño. – chilltemp

6

de chile funcionará si estás bien con los contratos que se comparten por el servicio . Si quieres que se separen intente esto:

host1 = new ServiceHost(typeof(MyService1)); 
host2 = new ServiceHost(typeof(MyService2)); 

host1.Open(); 
host2.Open(); 

public class MyService1 : IMyService1 
{ 
    #region IMyService1 
    #endregion 
} 

public class MyService2 : IMyService2 
{ 
    #region IMyService2 
    #endregion 
} 

Edit: Como Matt publicada, esto requeriría varios puntos finales para cada servicio/contrato

+0

Esto es perfecto. Es exactamente lo que estaba buscando cuando comencé a leer este hilo. Inicialmente pensé que esto sería imposible de juzgar a partir de la esencia de este hilo, pero funciona bien. –

10

Esta respuesta es una respuesta más a la observación de la respuesta aceptada de Chilltemp.

Sam, realmente debería determinar por qué necesita 10-50 contratos y tratar de encontrar otra solución. Miré por encima de WCF Juval Lowy estándares de codificación (que se encuentra en http://www.idesign.net/) y encontramos las siguientes referencias:

3 contratos de servicio ... 4. Evita los contratos con uno de los miembros. 5. Esforzarse por tener de tres a cinco miembros por contrato de servicio. 6. No tiene más de veinte miembros por contrato de servicio. Doce es probablemente el límite práctico.

No menciona un límite en las implementaciones de contratos (que puedo encontrar) pero no puedo imaginarlo viendo 50 contratos en un servicio como algo que se asemeja a una mejor práctica. Una solución que he encontrado que funciona bien es usar el uso compartido de miembros para funciones similares.

Por ejemplo, si utiliza el servicio WCF para realizar operaciones matemáticas en 2 valores, puede tener 4 miembros en el lado del servicio: Agregar (x, y), Restar (x, y), Multiplicar (x, y) , Divide (x, y) Si combina esto en un miembro más genérico y utiliza un objeto para pasar los datos necesarios, puede reducir fácilmente su número de miembros y aumentar la escalabilidad. Ejemplo: PeformCalculation (obj) donde obj tiene propiedades x, y, y acción (agregar, restar, multiplicar, dividir).

Espero que esto ayude.

+0

Juval está hablando de 3-5 miembros en un contrato. Estoy hablando de 10 a 50 contratos para un servicio (cada contrato contiene entre 3 y 5 miembros). Tal vez eso está creando la confusión? – Sam

+1

No es confusión, él no menciona un límite en los contratos, pero no me gustaría ir por el camino de tener 50 contratos en un servicio. Debería haber alguna forma de refactorización que se podría hacer en sus contratos para reducir el tamaño/conteo de ellos. Es tu aplicación, pero buscaría otras opciones. –

17

Actualmente me enfrento con el mismo problema, y ​​he decidido seguir con la implementación a continuación.No estoy seguro de si hay algún problema de rendimiento con tantos contratos de servicio, pero en mi implementación final probablemente tenga entre 10 y 15 contratos de servicio, por lo tanto, alrededor de 10-15 ServiceHosts.

Estoy alojando todos mis servicios WCF dentro de un solo servicio de Windows.

private void PublishWcfEndpoints() 
{ 
    var mappings = new Dictionary<Type, Type> 
    { 
     {typeof (IAuthenticationService), typeof (AuthenticationService)}, 
     {typeof(IUserService), typeof(UserService)}, 
     {typeof(IClientService), typeof(ClientService)} 
    }; 


    foreach (var type in mappings) 
    { 
     Type contractType = type.Key; 
     Type implementationType = type.Value; 

     ServiceHost serviceHost = new ServiceHost(implementationType); 
     ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(contractType, ServiceHelper.GetDefaultBinding(), 
                    Properties.Settings.Default.ServiceUrl + "/" + contractType.Name); 
     endpoint.Behaviors.Add(new ServerSessionBehavior()); 

     ServiceDebugBehavior serviceDebugBehaviour = 
      serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>(); 
     serviceDebugBehaviour.IncludeExceptionDetailInFaults = true; 

     log.DebugFormat("Published Service endpoint: {0}", Properties.Settings.Default.ServiceUrl); 

     serviceHost.Open(); 
     serviceHosts.Add(serviceHost); 
    } 

} 

Siéntase libre de comentar en este tipo de configurar, y si hay algún problema con él, sobre todo en función del rendimiento.

+0

aquí va complicado –

+0

Sería incluso mejor si utilizó un contenedor de inyección de dependencia para resolver las implementaciones =) – Th3B0Y

+0

La mejor solución que permite aislar y atribuir servicios individualmente, – bvj

1

¿Qué hay de dividirlo con una dirección base y múltiples servicios/contratos debajo? no estoy detrás de un developmachine este momento, pero algo como:

http://myserver/myservices/serviceA
http://myserver/myservices/serviceB
http://myserver/myservices/serviceC

Cada servicio de la aplicación de su propia ServiceContract.

Puede cambiar
public class WcfEntryPoint : IMyService1, IMyService2
a
public partial class WcfEntryPoint : IMyService1
public partial class WcfEntryPoint : IMyService2

Example

8

he encontrado otra solución a este número mediante el uso de una clase RoutingService. Cada contrato debe estar alojado en su propio ServiceHost, pero puede haber un RoutingService encima de todos ellos y presentarlos en un "punto final" unificado. También escribí un codeproject article al respecto. El código de ejemplo también está disponible en Bitbucket.

1

Nadie documentó enpoints. Whe utilizado más de una (como un grupo, de url común, por ejemplo http) debe utilizar la misma instancia de unión (no más), es decir,

Su muestra:

servicehost = new ServiceHost(typeof(MyService1)); 
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1"); 
servicehost.AddServiceEndpoint(typeof(IMyService2), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService2"); 
servicehost.Open(); 

debe haber sólo un nuevo Binding(), Probé a través de http.

servicehost = new ServiceHost(typeof(MyService1)); 
BasicHttpBinding binding = new BasicHttpBinding(); 
servicehost.AddServiceEndpoint(typeof(IMyService1),binding , "http://127.0.0.1:800/MyApp/MyService1"); 
servicehost.AddServiceEndpoint(typeof(IMyService2), binding, "http://127.0.0.1:800/MyApp/MyService2"); 
servicehost.Open(); 

Estoy totalmente de acuerdo con la implementación parcial de algunos contratos en pocos archivos.

0

¿Echaba de menos algo, o la solución más simple no se menciona aquí? La solución más simple es esta: no use interfaces múltiples para el servicio web.

Pero eso no significa que todavía pueda tener sus interfaces separadas. Es por eso que tenemos herencia de interfaz.

[ServiceContract] 
public interface IMetaSomeObjectService : ISomeObjectService1, ISomeObjectService2 
{ 
} 

La interfaz Meta hereda de todas las otras interfaces.

[ServiceContract] 
public interface ISomeOjectService1 
{ 
    [OperationContract] 
    List<SomeOject> GetSomeObjects(); 
} 

[ServiceContract] 
public interface ISomeOjectService2 
{ 
    [OperationContract] 
    void DoSomethingElse(); 
} 

Luego el servicio solo tiene la interfaz Meta.

public class SomeObjectService : IMetaSomeObjectService 
{ 
    public List<SomeOject> GetSomeObjects() 
    { 
     // code here 
    } 

    public void DoSomethingElse() 
    { 
     // code here 
    } 
} 
Cuestiones relacionadas