2011-01-13 7 views
4

Ich habe einen WCF-Dienst über diese tutorial erstellt. Das funktioniert super, hier keine Probleme. Jetzt hosste ich den Dienst in einer verwalteten Anwendung. Gleichzeitig möchte ich aber die Eingabe vom Client zum Dienst in der Host-Anwendung verwenden.Wie kommuniziert man zwischen dem WCF-Dienst und der Host-Anwendung?

Ich brauche keine Duplex-Kommunikation zwischen dem Client und dem Dienst. Ich brauche nur Kommunikation zwischen dem Service und der Host-Kommunikation.

Was wäre der beste Weg, damit umzugehen?

Antwort

3

Ich habe es mit den Informationen aus dieser question lösen. In dem wurde darauf hingewiesen, dass Serviceklassen auch an den Host übergeben werden können. Dann ist es so einfach, einen Ereignis-Listener hinzuzufügen, der auf Ereignisse vom Dienst reagiert.

+0

In diesem Fall wird Ihr Service Singleton sein. –

2

Es ist wie Kommunikation zwischen Threads. Sie benötigen eine gemeinsam genutzte Variable mit ordnungsgemäßer Synchronisation. Ihre Hostanwendung schreibt in diese Variable und Ihr Dienst kann von dieser Variablen lesen.

+0

Danke für Ihren Vorschlag. Okay, ich könnte sehen, dass das funktioniert. Aber wie greife ich auf Variablen Teil des Service-Objekts von der Host-Anwendung oder umgekehrt? Ich habe keinen Verweis auf den Dienst, da ich den Host.open() -Befehl zum Hosten des Dienstes verwende. – Martijn

+0

Sie greifen nicht auf Variablen in Dienstinstanz zu. Ihre Variablen müssen von bekannten Objekten geteilt werden. Zum Beispiel können Sie Singleton hinzufügen, das solche Variablen sowohl dem Dienst als auch dem Host zur Verfügung stellt. Ein anderer Ansatz ist die Verwendung des Service-Locators für das gemeinsame Objekt. –

+0

Meinst du, ich muss ein separates Objekt mit Singleton-Eigenschaften in der Host-Anwendung erstellen. Wie kann ich einen Verweis auf dieses Objekt von meinem Service erstellen? Mein ultimatives Ziel ist es, eine Funktion in der Host-Anwendung auszulösen, wenn der WCF-Dienst Daten vom Client empfängt. Würde dies mit der Singleton-Methode funktionieren? – Martijn

2

Es gibt ein Framework und Tutorial zur Verfügung, das scheint, dieses Problem recht gut zu behandeln WPF Service Host on Codeplex.

BEARBEITEN: Aktualisiert, um die Technik zu veranschaulichen, die von der WPF-Service-Host-Vorlage erstellt wurde.

Der WPF-Diensthost ist eine Vorlage für Visual Studio, mit der eine Skelettanwendung und ein Testclient erstellt werden. Ich werde die relevanten Stücke hier beschreiben.

Hier ist, was das Skelett Projekt wie folgt aussieht:

Skeleton Project

ClientServiceHost.cs

using System; 
using System.ServiceModel; 

namespace WPFServiceHost1.Service 
{ 
    public class ClientServiceHost : IDisposable 
    { 
     private bool _Initalized; 

     private ServiceHost _InnerServiceHost; 
     private MainWindow _MainWindow; 

     public ClientServiceHost(MainWindow mainWindow) 
     { 
      _MainWindow = mainWindow; 
      InitializeServiceHost(); 
     } 

     private void InitializeServiceHost() 
     { 
      try 
      { 
       ClientService clientService = new ClientService(_MainWindow); 
       _InnerServiceHost = new ServiceHost(clientService); 

       _InnerServiceHost.Opened += new EventHandler(_InnerServiceHost_Opened); 
       _InnerServiceHost.Faulted += new EventHandler(_InnerServiceHost_Faulted); 
       _InnerServiceHost.Open(); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception("Unable to initialize ClientServiceHost", ex); 
      } 
     } 

     void _InnerServiceHost_Opened(object sender, EventArgs e) 
     { 
      _Initalized = true; 
     } 

     void _InnerServiceHost_Faulted(object sender, EventArgs e) 
     { 
      this._InnerServiceHost.Abort(); 

      if (_Initalized) 
      { 
       _Initalized = false; 
       InitializeServiceHost(); 
      } 
     } 

     #region IDisposable Members 

     public void Dispose() 
     { 
      try 
      { 
       _InnerServiceHost.Opened -= _InnerServiceHost_Opened; 
       _InnerServiceHost.Faulted -= _InnerServiceHost_Faulted; 
       _InnerServiceHost.Close(); 
      } 
      catch 
      { 
       try { _InnerServiceHost.Abort(); } 
       catch { } 
      } 
     } 
     #endregion 
    } 
} 

MainWindow.xaml

<Window x:Class="WPFServiceHost1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="WPFServiceHost1" Height="344" Width="343" Closing="Window_Closing"> 
    <Grid> 
     <Label Height="28" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="119">Messages received:</Label> 
     <ListBox Margin="21,38,26,21" Name="listBox1" /> 
    </Grid> 
</Window> 

MainWindow.xaml.cs

IClientService.cs

using System.ServiceModel; 

namespace WPFServiceHost1.Service 
{ 
    [ServiceContract(Namespace = "urn:WPFServiceHost")] 
    public interface IClientService 
    { 
     [OperationContract] 
     void ClientNotification(string message); 
    } 
} 

ClientService.cs

using System; 
using System.ServiceModel; 

namespace WPFServiceHost1.Service 
{ 
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false)] 
    public class ClientService : IClientService 
    { 
     private MainWindow _MainWindow; 

     public ClientService(MainWindow window) 
     { 
      _MainWindow = window; 
     } 

     #region IClientService Members 
     public void ClientNotification(string message) 
     { 
      try 
      { 
       _MainWindow._SyncContext.Send(state => 
       { 
        _MainWindow.listBox1.Items.Add(message); 
       }, null); 
      } 
      catch (Exception ex) 
      { 
       throw new FaultException(ex.Message); 
      } 
     } 
     #endregion 
    } 
} 

App.config

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
     <behaviors> 
      <serviceBehaviors> 
       <behavior name="ClientServiceBehavior"> 
        <serviceDebug includeExceptionDetailInFaults="false" /> 
       </behavior> 
      </serviceBehaviors> 
     </behaviors> 
     <services> 
      <service behaviorConfiguration="ClientServiceBehavior" 
       name="WPFServiceHost1.Service.ClientService"> 
       <endpoint address="ClientService" binding="basicHttpBinding" contract="WPFServiceHost1.Service.IClientService"/> 
       <host> 
        <baseAddresses> 
         <add baseAddress="http://localhost:8010" /> 
        </baseAddresses> 
       </host> 
      </service> 
     </services> 
    </system.serviceModel> 
</configuration> 

Und die Testclient, Program.cs:

using System; 
using System.ServiceModel; 
using System.Threading; 

namespace TestClient 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IClientService proxy = null; 

      try 
      { 
       proxy = ChannelFactory<IClientService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:8010/ClientService")); 
       Console.WriteLine("Press <Enter> when ClientService is running."); 
       Console.ReadLine(); 
       Console.WriteLine(); 

       Console.WriteLine("Sending a single message to ClientService"); 
       proxy.ClientNotification("Hello from TestClient"); 

       Console.WriteLine(); 

       Console.Write("Enter a valid number to load test ClientService: "); 
       string result = Console.ReadLine(); 
       int testCount = Convert.ToInt32(result); 
       int counter = 0; 
       object counterLock = new object(); 

       while (true) 
       { 
        lock (counterLock) 
        { 
         Thread t = new Thread(() => proxy.ClientNotification(string.Format("Load test from TestClient: {0}", ++counter))); 
         t.Start(); 
        } 

        if (counter == testCount) 
         break; 
       } 

       Console.ReadLine(); 
      } 
      finally 
      { 
       ICommunicationObject co = proxy as ICommunicationObject; 
       try 
       { 
        co.Close(); 
       } 
       catch { co.Abort(); } 
      } 

      Console.ReadLine(); 
     } 
    } 
} 
Verwandte Themen