2011-01-13 91 views
4

我通过这个tutorial创建了一个WCF服务。这很好,这里没有问题。 现在我在托管应用程序中托管服务。但是同时我想用客户端的输入来访问宿主应用程序中的服务。如何在WCF服务和主机应用程序之间进行通信?

我不需要客户端和服务之间的双工通信。我只需要服务和主机通信之间的通信。

什么是解决这个问题的最佳方法?

回答

3

我设法使用此question的信息来解决它。有人指出,服务类也可以传递给主机。然后就像添加一个响应服务事件的事件监听器一样简单。

2

这就像线程之间的通信。您需要一些具有适当锁定/同步的共享变量。您的主机应用程序将写入此变量,您的服务将能够从该变量中读取。

+0

感谢您的建议。好的,我可以看到这个工作。但我怎么访问从主机应用程序或反之亦然服务对象的变量的一部分?我没有对服务的引用,因为我用的是Host.open()命令来托管服务。 – Martijn 2011-01-13 13:04:46

+0

您不访问服务实例中的变量。您的变量必须由众所周知的对象共享。例如,你可以输入单身,这会将这些变量暴露给服务和主机。其他方法是使用服务定位器来共享对象。 – 2011-01-13 13:09:02

2

有一个框架和指南可用,这似乎相当不错WPF Service Host on Codeplex处理这个问题。

编辑:更新,以说明在WPF服务主机模板创建的技术。

WPF服务主机是Visual Studio的模板,用于创建骨架应用程序和测试客户端。我将在这里描述相关的部分。

下面是框架项目的样子:

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

using System.Threading; 
using WPFServiceHost1.Service; 

namespace WPFServiceHost1 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public SynchronizationContext _SyncContext = SynchronizationContext.Current; 
     private ClientServiceHost _ClientServiceHost; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      _ClientServiceHost = new ClientServiceHost(this); 
     } 

     private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) 
     { 
      _ClientServiceHost.Dispose(); 
     } 
    } 
} 

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> 

而且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(); 
     } 
    } 
} 
相关问题