我通过这个tutorial创建了一个WCF服务。这很好,这里没有问题。 现在我在托管应用程序中托管服务。但是同时我想用客户端的输入来访问宿主应用程序中的服务。如何在WCF服务和主机应用程序之间进行通信?
我不需要客户端和服务之间的双工通信。我只需要服务和主机通信之间的通信。
什么是解决这个问题的最佳方法?
我通过这个tutorial创建了一个WCF服务。这很好,这里没有问题。 现在我在托管应用程序中托管服务。但是同时我想用客户端的输入来访问宿主应用程序中的服务。如何在WCF服务和主机应用程序之间进行通信?
我不需要客户端和服务之间的双工通信。我只需要服务和主机通信之间的通信。
什么是解决这个问题的最佳方法?
我设法使用此question的信息来解决它。有人指出,服务类也可以传递给主机。然后就像添加一个响应服务事件的事件监听器一样简单。
这就像线程之间的通信。您需要一些具有适当锁定/同步的共享变量。您的主机应用程序将写入此变量,您的服务将能够从该变量中读取。
有一个框架和指南可用,这似乎相当不错WPF Service Host on Codeplex处理这个问题。
编辑:更新,以说明在WPF服务主机模板创建的技术。
WPF服务主机是Visual Studio的模板,用于创建骨架应用程序和测试客户端。我将在这里描述相关的部分。
下面是框架项目的样子:
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();
}
}
}
感谢您的建议。好的,我可以看到这个工作。但我怎么访问从主机应用程序或反之亦然服务对象的变量的一部分?我没有对服务的引用,因为我用的是Host.open()命令来托管服务。 – Martijn 2011-01-13 13:04:46
您不访问服务实例中的变量。您的变量必须由众所周知的对象共享。例如,你可以输入单身,这会将这些变量暴露给服务和主机。其他方法是使用服务定位器来共享对象。 – 2011-01-13 13:09:02