2009-11-21 22 views
11

Necesito ejecutar un montón de procesos conectables en un servicio de Windows en mi servidor y quiero crear una interfaz de usuario que me permita interactuar con cada uno de los complementos en uso por el servicioCrear una interfaz de usuario para supervisar e interactuar con un servicio de Windows en ejecución

¿Cuál es el método (o métodos) más común para la comunicación entre una interfaz de usuario y un servicio de Windows de larga ejecución? Estoy pensando en proporcionar una ubicación intermedia, como una base de datos y el uso de algún tipo de cola de mensajes para emitir comandos al servicio. ¿Alguno de ustedes ha implementado un enfoque así o algún otro enfoque superior? ¿Qué problemas has encontrado en el proceso?

Respuesta

32

No utilizar la comunicación remota! Si bien funcionará, Microsoft dice que la comunicación remota es una tecnología heredada y que todas las nuevas aplicaciones distribuidas deben desarrollarse utilizando WCF. Ver here para más detalles.

Windows Communication Foundation (WCF) es la forma recomendada para que dos procesos .NET se comuniquen entre sí. WCF proporciona un modelo de programación unificada que simplifica enormemente el desarrollo distribuido al abstraer muchas de las complejidades asociadas con mecanismos de comunicación específicos, por ejemplo, sockets, pipes, etc.

Dado los detalles de su situación, le sugiero que haga cada complemento de servicio de Windows un servicio WCF. Para cada servicio WCF, es decir, complemento, defina la interfaz que necesita exponer en su UI. La interfaz es simplemente una interfaz C# adornada con el atributo ServiceContract. Esta interfaz contiene los métodos, cada uno de los cuales está adornado con el atributo OperationContract, que su interfaz de usuario usará para comunicarse con el servicio WCF (complemento). Estos métodos pueden aceptar y devolver cualquier tipo de .NET serializable o, como suele ser el caso, sus propios tipos personalizados. Para usar tipos personalizados con WCF, simplemente decorelos con el atributo DataContract y marque los miembros que desea intercambiar a través de WCF con el atributo DataMember.

Una vez que haya definido su interfaz ServiceContract, defina una clase que implemente esa interfaz. Cada método OperationContract hace lo que tiene que hacer, por ejemplo, interactuar con la base de datos, calcular algún valor, etc. Una vez que haya hecho esto, habrá definido efectivamente un servicio WCF. He aquí una breve, pero de trabajo, ejemplo:

using System.ServiceModel; 
namespace AdditionServiceNamespace 
{ 
    [DataContract] 
    public class Complex 
    { 
     [DataMember] 
     public int real; 
     [DataMember] 
     public int imag; 
    } 
    [ServiceContract] 
    public interface IAdditionService 
    { 
     [OperationContract] 
     Complex Add(Complex c1, Complex c2); 
    } 
    public class AdditionService : IAdditionService 
    { 
     public Complex Add(Complex c1, Complex c2) 
     { 
      Complex result = new Complex(); 
      result.real = c1.real + c2.real; 
      result.imag = c1.imag + c2.imag; 
      return result; 
     } 
    } 
} 

El siguiente paso es la sede de este servicio WCF de modo que esté disponible para ser utilizado por la interfaz de usuario. Dado que va a utilizar un servicio de Windows, que alberga su servicio WCF se realiza con bastante facilidad en el OnStart() de devolución de llamada de su servicio de Windows, así:

using System.ServiceModel; 
using System.ServiceProcess; 
using AdditionServiceNamespace; 
namespace WindowsServiceNamespace 
{ 
    public class WindowsService : ServiceBase 
    { 
     static void Main() 
     { 
      ServiceBase[] ServicesToRun = new ServiceBase[] 
      { new WindowsService() }; 
      ServiceBase.Run(ServicesToRun); 
     } 
     private ServiceHost _host; 
     public WindowsService() 
     { 
      InitializeComponent(); 
     } 
     protected override void OnStart(string[] args) 
     { 
      _host = new ServiceHost(typeof(AdditionService)); 
      _host.Open(); 
     } 
     protected override void OnStop() 
     { 
      try 
      { 
       if (_host.State != CommunicationState.Closed) 
       { 
        _host.Close(); 
       } 
      } 
      catch 
      { 
       // handle exception somehow...log to event viewer, for example 
      } 
     } 
    } 
} 

Lo único que queda por hacer es definir un archivo app.config para su servicio de Windows que configurará ciertos aspectos necesarios de su servicio WCF. Esto puede parecer excesivo, pero tenga dos cosas en mente. En primer lugar, Visual Studio le proporciona un archivo app.config básico automáticamente cuando agrega una clase de servicio WCF a su proyecto. En segundo lugar, la aplicación.El archivo de configuración le proporciona una gran cantidad de control sobre su servicio WCF sin requerir cambios en el código. Aquí está el compañero archivo app.config para el ejemplo anterior:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
     <services> 
      <service name="AdditionServiceNamespace.MyAdditionService" 
        behaviorConfiguration="default"> 
       <endpoint name="AdditionService" 
        address="net.pipe://localhost/AdditionService" 
        binding="netNamedPipeBinding" 
        contract="AdditionServiceNamespace.IAdditionService" /> 
       <endpoint address="net.pipe://localhost/AdditionService/MEX" 
        binding="mexNamedPipeBinding" 
        contract="IMetadataExchange" /> 
      </service> 
     </services> 
     <behaviors> 
      <serviceBehaviors> 
       <behavior name="default> 
        <serviceMetadata /> 
       </behavior> 
      </serviceBehaviors> 
     </behaviors> 
    </system.serviceModel> 
</configuration> 

Tenga en cuenta que el servicio WCF AdditionService tiene dos puntos finales. El punto final de intercambio de metadatos se usa para la generación de código por parte del cliente, por lo que ignórelo por el momento. El primer punto final está configurado para usar el NetNamedPipeBinding. Este es el enlace que se usará si su UI y el servicio de Windows se ejecutarán en la misma máquina (consulte here para obtener un diagrama de flujo al seleccionar el enlace apropiado para usar). Sin embargo, este enlace no se puede usar si su UI y el servicio de Windows se ejecutarán en máquinas diferentes. En ese caso, podría usar el NetTcpBinding como reemplazo. Para sustituir la NetTcpBinding para la NetNamedPipeBinding, sólo tendría que tenga que cambiar la dirección y la unión del punto final, así:

<endpoint name="AdditionService" 
      address="net.tcp://<machine hostname here>/AdditionService" 
      binding="netTcpBinding" 
      contract="AdditionServiceNamespace.IAdditionService" /> 

No se requieren cambios en el código! Realice el cambio, reinicie su servicio y su servicio WCF ahora está disponible para máquinas remotas. Incluso puede permitir múltiples puntos finales para el mismo servicio WCF si así lo desea. El punto es que el archivo app.config ofrece una tremenda cantidad de flexibilidad sin requerir cambios en el código.

Eso es todo! Ahora tiene un servicio WCF alojado dentro de su servicio de Windows disponible para que lo use su UI.

Entonces, ¿cómo funciona el lado de la IU, es decir, el lado del cliente?

Aquí es donde entra en juego el poder real de WCF. Al comenzar con WCF, lo más fácil es aprovechar las capacidades de generación de código de Visual Studio. Asegúrese de que su servicio de Windows (el que aloja AdditionService) se esté ejecutando. En su proyecto de IU, haga clic con el botón derecho en su proyecto en el Explorador de soluciones y seleccione Agregar referencia de servicio ... opción de menú. En el cuadro Dirección, escriba net.pipe://localhost/AdditionService y haga clic en el botón Ir. Debería ver el servicio adicional en la lista de Servicios . En el cuadro Namespace, escriba AdditionService y haga clic en el botón OK.

La realización de estos pasos generará un proxy de cliente y un archivo app.config correctamente definido que se agregarán a su proyecto de UI. Este proxy del cliente se convierte en su API AdditionService del lado del cliente, y se utiliza de esta manera:

using TestConsoleApp.AdditionService; 
namespace TestConsoleApp 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      AdditionServiceClient client = new AdditionServiceClient(); 
      Complex c1 = new Complex(), c2 = new Complex(); 
      c1.real = 3; c1.imag = 5; 
      c2.real = 1; c2.imag = 7; 
      Complex result = client.Add(c1, c2); 
     } 
    } 
} 

Aviso lo simple que es. Básicamente, se crea una instancia de un cliente proxy, AdditionServiceClient. Luego se crean dos objetos Complex. Finalmente, se invoca el método Add() en el proxy del cliente y se devuelve un resultado Complex.

Lo que ocurre entre bastidores es que el método Add() del proxy del cliente está realmente pasando los dos objetos Complex al servicio WCF de AdditionService alojado en el servicio de Windows. El AdditionService realiza la adición y luego devuelve el resultado. Todo esto sucede en una tubería con nombre, pero se da cuenta de que aquí no hay ningún código específico para la tubería con nombre. WCF ha abstraído toda esa complejidad detrás de un modelo de programación definido por la interfaz IAdditionService.

Sé que esta es una gran cantidad de información para digerir, pero espero que sea evidente cuán poderosa y fácil de usar puede ser WCF. Por supuesto, este ejemplo solo afecta a un pequeño subconjunto de todo lo que está disponible dentro de WCF.

Al final, sin embargo, WCF debería ser el mecanismo que usa para comunicarse entre su UI y su servicio de Windows. Para obtener más información, recomendaría el libro de Juval Lowy Programming WCF Services para todo lo relacionado con WCF. También puede visitar su sitio web, IDesign.net, para obtener muestras gratuitas del código WCF. Para obtener más información sobre WCF, mire este free video en dnrTV. Cubre el propósito de WCF y demuestra la programación de WCF a través de algunos ejemplos fáciles de seguir.

+0

¡Gracias por la respuesta detallada! Es por eso que amo este sitio: D –

+0

Muchas gracias. Pase esto para encontrar esto cuando investigue un "envoltorio/adaptador de servicio de Windows" para una aplicación Java; estaba considerando comprar un costoso envoltorio listo para usar (para cualquier aplicación de Java) ... leyendo esta respuesta maravillosamente informativa, el mejor camino es claro: quitar el polvo de Visual Studio y las gafas C :-) –

0

Lo mejor que puede hacer es utilizar .NET remotamente a través de un canal IPC.

Si bien parece complicado de configurar, es bastante fácil la segunda vez.

Le sugiero que juegue con algunas muestras primero al exponer objetos que se pueden controlar desde una aplicación a otra.

No he usado colas de mensajes antes, así que no puedo comentar sobre eso.

+0

Remoting está efectivamente en desuso - un servicio WCF autohospedado sería el equivalente contemporáneo, config es probablemente el mismo. – Murph

+0

@Murph: ¿WTF? ¿Cómo se puede desaprovechar la comunicación remota a favor de WCF? ¿Dónde leíste esta tontería? – leppie

+1

Remoting es ** ya no ** el enfoque recomendado; WCF es. http://msdn.microsoft.com/en-us/library/kwdt6w2k(VS.85).aspx –

Cuestiones relacionadas