2011-05-20 27 views
7

Tengo un contrato de servicio WCF que es básicamente el patrón Publish Subscriber.¿Puedo llamar localmente un método en un servicio WCF autohospedado?

El servicio WCF está alojado dentro del servicio de Windows del que quiero publicar. Los clientes se suscriben a los mensajes y cuando el servicio de Windows hace algo que publica para todos los clientes.

Para alojar el servicio que he declarado una clase ServiceHost y de la Clase contrato tiene un método que no está marcado en la interfaz sino que se implementa en la clase de publicar.

Quiero ser capaz de llamar a este método de forma local (no ir a través de WCF) que luego se publica el mensaje a través de devoluciones de llamada.

Parece que no puedo pasar de ServiceHost a la instancia de la clase de contrato.

¿Es esto posible y, de ser así, cómo? Sé que la solución alternativa es tener un cliente integrado en el servicio también, pero parece un poco extraño crear un cliente para conectarse a sí mismo.

Gracias de antemano

DJIDave

app.config

<system.serviceModel> 
    <services> 
     <service behaviorConfiguration="Processor.Wcf.ServiceBehavior" 
     name="Processor.Wcf.ProcessorService"> 
     <endpoint address="net.tcp://localhost:9000/processor/service" 
       binding="netTcpBinding" name="procService" 
       bindingConfiguration="netTcpBindingConfig" 
       contract="Processor.Wcf.IProcessorService"/> 
     <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
      <host> 
      <baseAddresses> 
       <add baseAddress="http://localhost:8732/Design_Time_Addresses/Processor.Wcf/Service1/" /> 
      </baseAddresses> 
      </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="Processor.Wcf.ServiceBehavior"> 
      <!-- To avoid disclosing metadata information, 
      set the value below to false and remove the metadata endpoint above before deployment --> 
      <serviceMetadata httpGetEnabled="True"/> 
      <!-- To receive exception details in faults for debugging purposes, 
      set the value below to true. Set to false before deployment 
      to avoid disclosing exception information --> 
      <serviceDebug includeExceptionDetailInFaults="False" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <netTcpBinding> 
     <binding name="netTcpBindingConfig" 
       closeTimeout="00:01:00" 
       openTimeout="00:01:00" 
       receiveTimeout="00:10:00" 
       sendTimeout="00:01:00" 
       transactionFlow="false" 
       transferMode="Buffered" 
       transactionProtocol="OleTransactions" 
       hostNameComparisonMode="StrongWildcard" 
       listenBacklog="10" 
       maxBufferPoolSize="524288" 
       maxBufferSize="65536" 
       maxConnections="10" 
       maxReceivedMessageSize="65536"> 
      <readerQuotas maxDepth="32" 
         maxStringContentLength="8192" 
         maxArrayLength="16384" 
         maxBytesPerRead="4096" 
         maxNameTableCharCount="16384" /> 
      <reliableSession ordered="true" 
          inactivityTimeout="00:10:00" 
          enabled="false" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 

    </system.serviceModel> 

Respuesta

7

A menos que usted proporciona la referencia de instancia de servicio a la ServiceHost como un parámetro del constructor, no hay una manera de tener la ServiceHost le proporciona una referencia de instancia de servicio. Si proporciona esa referencia de instancia, entonces está creando un servicio singleton que generalmente no es una buena idea.

Para mantener el servicio tal como está configurado, tendrá que llamarlo a través de un cliente. Esto es realmente más fácil de lo que piensas. Como su código de host tiene acceso al contrato de servicio, puede usarlo con el ChannelFactory class para obtener un proxy para el servicio. Además del contrato de servicio, todo lo que tiene que proporcionar es el nombre y ChannelFactory hará el resto. A continuación se muestra un ejemplo de cómo hacer esto:

private IMyServiceContract GetLocalClient(string serviceEndpointName) 
{ 
    var factory = new ChannelFactory<IMyServiceContract>(serviceEndpointName); 
    return factory.CreateChannel(); 
} 

ACTUALIZACIÓN: Junto con este enfoque, se debe considerar la posibilidad de que un servicio se exponen NetNamedPipeBinding endpoint para mejorar el rendimiento. Este enlace hace prácticamente todo en la memoria y es el enlace más rápido para la misma invocación de servicio de la máquina.

+0

Gracias por la respuesta, puedo obtener la fábrica con éxito, pero cuando trato de llamar a CreateChannel obtengo "La propiedad Address en ChannelFactory.Endpoint era nulo. El Endpoint de ChannelFactory debe tener una Dirección válida especificada.". Publicaré app.config como una edición en la publicación original. – DJIDave

+0

Si se lanza la excepción, incluso si el nombre del punto final que está pasando la función es "procService", puede ser un problema de permiso. Esto es solo una suposición, pero la cuenta para el servicio de Windows es la utilizada para acceder al servicio WCF. Es posible que no tenga permiso para invocar el servicio ya que requiere autenticación de Windows. Si no es así, le recomendaría que agregue y configure netNamedPipeBinding en lugar de intentar solucionar el enlace TCP, ya que es una mejor opción para lo que está haciendo. –

+0

Gracias, ahora lo tengo trabajando usando el método anterior. – DJIDave

2

Para un servicio WCF que crea una instancia más de una vez (no único), puede mantener una lista que contenga la función de devolución de llamada correspondiente de cada instancia como se indica aquí: mdsn. Puede llamar al método CallClients() (de este ejemplo de MSDN) desde el código de alojamiento directamente ya que es un miembro estático de la clase de servicio. Esta es la única manera que encontré ..

0

A menos que usted proporciona la referencia de instancia de servicio a la ServiceHost como parámetro constructor,

Esta línea de solución de Sixto resuelven las cosas para mí. Crédito y gracias a this post también.

Estoy utilizando un enlace dúplex en este momento.


El concepto clave es que se puede pasar en una instancia Typeo un a la ServiceHost constructor.

Así que lo que había antes era:

ServiceHost host = new ServiceHost(typeof(MyService), myUri); 

Lo que necesitaba era:

MyService service = new MyService(foo); // Can now pass a parameter 
ServiceHost host = new ServiceHost(service, myUri); 

Además, tenía que marcar MyService con

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 

... y ahora Puedo llamar a los métodos del host desde dentro del servicio.

Sin embargo, tenga en cuenta que la instancia que ha creado no tendrá un OperationContext si se llama a sus métodos directamente: https://stackoverflow.com/a/15270541/385273

Buena suerte!

Cuestiones relacionadas