2010-11-29 7 views
6

Dado:
- la aplicación - interfaz gráfica de usuario de escritorio (WPF) aplicación .NET
- ventanas servicio de observación para la aplicación (.NET también)Conexión a través de canalización con nombre de servicio de Windows (Sesión # 0) para aplicación de escritorio (Sesión # 1)

El servicio de Windows periódicamente "hace ping" a la aplicación para asegurarse de que esté en buen estado (y si no es así, winservice la reiniciará).
Iba a implementar "pinging" a través de named pipes. Para hacer las cosas más simples, decidí hacerlo con WCF. La aplicación aloja un servicio WCF (una operación Ping que devuelve algo). El servicio de Windows es un cliente para este servicio WCF, lo invoca periódicamente en función de un temporizador.

Eso es todo en Windows 7.
El servicio de Windows se ejecuta en LocalService (en la sesión # 0).
La aplicación de escritorio se está ejecutando bajo el usuario actualmente conectado (en la sesión n. ° 1).

El problema: servicio
Windows no puede ver WCF punto final (con NetNamedPipeBinding) creada en y ser escuchado en la aplicación de escritorio. Eso significa que en llamada a través del proxy wcf obtengo esta excepción: "El punto final de la tubería 'net.pipe: // localhost/HeartBeat' no se pudo encontrar en su máquina local"

Estoy seguro de que el código está bien, porque otra aplicación de escritorio (en la sesión n. ° 1) puede ver el punto final.

Obviamente aquí estoy tratando con algunas cosas de seguridad para el aislamiento de objetos del sistema Win32. Pero creo que debería haber una forma de resolver las restricciones con las que me he encontrado.
Puedo sacrificar el enfoque de WCF y seguir el camino de NamedPipe en bruto.

+0

¿Está seguro de que el servicio de Windows está intentando abrir el canal DESPUÉS de que se ejecuta la aplicación de escritorio? Cuando el servicio de Windows "no puede ver" el punto final WCF, ¿cuáles son los detalles de la excepción? –

+0

> # 1: sí, estoy seguro, porque winservice está haciendo esto (llamando por wcf) periódicamente (en bucle infinito). – Shrike

+0

> # 2: el servicio winservice "no puede ver" significa que al llamar a un proxy wcf obtengo la siguiente excepción: "El extremo del conducto 'net.pipe: // localhost/HeartBeat' no se pudo encontrar en su máquina local" – Shrike

Respuesta

6

Una solución más fácil sería utilizar un contrato dúplex de WCF con el servicio de Windows que aloja el servicio WCF. La aplicación cliente llamará a una operación en el servicio para registrarse, cuando se inicie. El ping sería entonces una operación invocada periódicamente por el servicio en el contrato de devolución de llamada del cliente, al que respondería la aplicación.

La visibilidad del servicio funciona de esta manera, porque el servicio de Windows se puede ejecutar con SeCreateGlobalPrivilege, por lo que el objeto de memoria compartido mediante el cual el servicio publica el nombre puede crearse en el espacio de nombres Global kernel, visible para otras sesiones. Las aplicaciones interactivas no pueden obtener fácilmente ese privilegio en Windows7, por lo que los servicios de WCF en dichas aplicaciones se vuelven a publicar en el espacio de nombres del kernel local, visible solo dentro de su propia sesión.

+0

una idea interesante, lo comprobaré mañana, gracias. – Shrike

+0

funcionó para mí –

4

Finalmente, he encontrado una solución: usar Canalizaciones con nombre de System.IO.Pipes directamente. Parece que la implementación de soporte de tuberías de WCF no usa System.IO.Pipes.

servidor:

using (var pipeServer = new NamedPipeServerStream("mypipe", PipeDirection.Out, 1)) 
{ 
    try 
    { 
     while (true) 
     { 
      // #1 Connect: 
      try 
      { 
       pipeServer.WaitForConnection(); 
      } 
      catch (ObjectDisposedException) 
      { 
       yield break; 
      } 
      if (ae.IsCanceled()) 
       return; 

      // #2: Sending response: 
      var response = Encoding.ASCII.GetBytes(DateTime.Now.ToString()); 
      try 
      { 
       pipeServer.Write(response, 0, response.Length); 
      } 
      catch (ObjectDisposedException) 
      { 
       return; 
      } 

      // #3: Disconnect: 
      pipeServer.Disconnect(); 
     } 
    } 
    finally 
    { 
     if (pipeServer.IsConnected) 
      pipeServer.Disconnect(); 
    } 
} 

cliente:

using (var pipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.In)) 
{ 
    try 
    { 
     try 
     { 
      pipeClient.Connect(TIMEOUT); 
     } 
     catch(TimeoutException ex) 
     { 
      // nobody answers to us 
      continue; 
     } 
     using (var sr = new StreamReader(pipeClient)) 
     { 
      string temp; 
      while ((temp = sr.ReadLine()) != null) 
      { 
       // got response 
      } 
     } 
    } 
    catch(Exception ex) 
    { 
     // pipe error 
     throw; 
    } 
} 
Cuestiones relacionadas