2010-11-29 4 views
6

Gegeben:
- die Anwendung - Desktop-GUI (WPF) .NET app
- Windows-Dienst für die Anwendung beobachten (.NET auch)Verbindung über Named Pipe von Windows-Dienst (Session # 0) zu Desktop-Anwendung (Session # 1)

Der Windows-Dienst "pingt" regelmäßig Anwendung, um sicherzustellen, dass es gesund ist (und wenn es nicht ist winservice wird es neu starten).
Ich würde "pingen" über Named Pipes implementieren. Um die Dinge einfacher zu machen, habe ich beschlossen, es mit WCF zu machen. Die Anwendung hostet einen WCF-Dienst (eine Operation, die etwas zurückgibt). Der Windows-Dienst ist ein Client für diesen WCF-Dienst und ruft ihn auf der Grundlage eines Zeitgebers periodisch auf.

Das ist alles in Windows 7.
Windows-Dienst läuft unter LocalService (in Sitzung # 0).
Desktop-Anwendung läuft unter derzeit angemeldeten Benutzer (in Sitzung # 1).

Das Problem:
Windows-Dienst WCF Endpunkt nicht sehen kann (mit NetNamedPipeBinding) erstellt in und in Desktop-Anwendung gehört zu werden. Das bedeutet, dass bei Aufruf über den Proxy-Server ich diese Ausnahme bekomme: "Der Pipe-Endpunkt 'net.pipe: // localhost/HeartBeat' konnte auf Ihrem lokalen Rechner nicht gefunden werden"

Ich bin mir sicher Code ist ok, denn Eine andere Desktopanwendung (in Sitzung 1) kann den Endpunkt sehen.

Offensichtlich hier habe ich mit einigen Sicherheits-Sachen für Win32-System-Objektisolierung beschäftigt. Aber ich glaube, es sollte einen Weg geben, um Workaround-Einschränkungen, denen ich begegnet bin.
Ich kann den WCF-Ansatz opfern und den rohen NamedPipe-Weg gehen.

+0

Sind Sie sicher, dass der Windows-Dienst versucht, den Kanal zu öffnen, nachdem die Desktop-Anwendung ausgeführt wird? Wenn der Windows-Dienst den WCF-Endpunkt nicht sehen kann, was sind die Details der Ausnahme? –

+0

> # 1: ja, da bin ich mir sicher, weil der winservice das (per wff anruf) periodisch (in endlosschleife) macht. – Shrike

+0

> # 2: Der Winservice "kann nicht sehen" bedeutet, dass beim Aufruf eines wcf-Proxy die folgende Ausnahme auftritt: "Der Pipe-Endpunkt 'net.pipe: // localhost/HeartBeat' konnte auf Ihrem lokalen Rechner nicht gefunden werden" – Shrike

Antwort

6

Eine einfachere Lösung könnte sein, einen WCF-Duplex-Vertrag mit dem Windows-Dienst zu verwenden, um den WCF-Hosting-Service. Die Client-App würde eine Operation auf dem Dienst aufrufen, um sich selbst beim Start zu registrieren. Der Ping wäre dann ein Vorgang, der periodisch vom Dienst im Callback-Vertrag des Clients aufgerufen wird, auf den die App antworten würde.

Die Diensttransparenz funktioniert auf diese Weise, da der Windows-Dienst mit SeCreateGlobalPrivilege ausgeführt werden kann. Daher kann das gemeinsam genutzte Speicherobjekt, über das der Pipe-Name vom Dienst veröffentlicht wird, im für andere Sitzungen sichtbaren globalen Kernel-Namespace erstellt werden. Interaktive Anwendungen können diese Berechtigung in Windows 7 nicht ohne weiteres erhalten, weshalb WCF-Dienste in solchen Anwendungen darauf zurückgreifen, die Pipe im lokalen Kernel-Namespace zu veröffentlichen, der nur innerhalb ihrer eigenen Sitzung sichtbar ist.

+0

eine interessante Idee, ich werde es morgen überprüfen, danke. – Shrike

+0

es funktionierte für mich –

4

Endlich habe ich eine Lösung gefunden - Named Pipes von System.IO.Pipes direkt verwenden. Es scheint, dass die WCF-Pipes-Implementierung keine System.IO.Pipes verwendet.

Server:

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

Kunde:

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