WCF 单实例
WCF 如何用于创建应用程序的单个实例
引言
有些应用程序希望在任何时候只有一个实例在运行。
要创建一个单实例应用程序,需要满足两个条件:
- 应用程序应该能够识别自身是否已经有实例在运行。
- 如果是,则通知第一个实例,并让第一个实例来处理这种情况。
由于这两个实例是完全不同的进程,因此涉及到进程间通信。WCF 是解决此问题的一种较简单的方案(例如,使用 WindowsFormsApplicationBase
、IPC 和远程调用)。
Using the Code
示例应用程序包含两个窗口。一个是启动窗体,它通过启动员工详细信息输入窗体来保存员工详细信息到 XML 文件。
要求是,每次运行应用程序时,都应打开员工详细信息窗体。对于第一次运行,它通常会打开该窗体。
当调用另一个实例时,第一个实例会收到第二个实例的通知,并提示用户是否关闭窗体,如图所示:

根据用户响应,它会关闭旧窗体或打开一个新的员工详细信息窗体(请注意下图中的环绕标题)。
因此,每次运行应用程序时,只会打开一个窗体。

现在让我们看看代码…
定义一个接口,通过该接口客户端(另一个实例)可以与服务器(第一个实例)通信。
使用“ServiceContract
”装饰接口,以将其暴露给客户端。
只有装饰为“ OperationContract
”的方法对客户端可见。
通过 Signal()
方法,客户端与服务器通信。
[ServiceContract]
public interface IServiceContract
{
/// <summary>
/// Signals this instance.
/// </summary>
[OperationContract]
void Signal();
}
“Service
”类实现了上述契约。
请注意,InstanceContextMode
设置为 Single
。如果将服务实例传递给服务宿主,则这是必需的。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service : IServiceContract
{
public EmployeeDetailsWindow window;
private static int formNumber;
void IServiceContract.Signal()
{
string strText = "Other instance is selected.\n";
strText =strText +"Do you want to close this and open the other ?";
MessageBoxResult result =
MessageBox.Show(strText, "Close", MessageBoxButton.YesNo);
bool blnInstanceClosed =
result == MessageBoxResult.Yes ? true : false;
if (blnInstanceClosed)
{
CloseEmployeeWindow();
Run();
}
else
{
if (window != null)
window.Activate();
}
}
}
InstanceMutex
类有两个函数“IsInstanceRunning
”和“StartService
”。
当“IsInstanceRunning
”请求通道时,如果通道不存在,则会抛出“EndPointNotFoundException
”。
这意味着这是第一个实例。它必须通过调用“StartService
”成为服务器。
“StartService
”创建服务宿主并打开它以服务于请求。
public class InstanceMutex
{
public static ServiceHost host;
public static bool IsInstanceRunning(string channelUri)
{
ChannelFactory<IServiceContract> factory =
new ChannelFactory<IServiceContract>
(new NetNamedPipeBinding(), new EndpointAddress(channelUri));
IServiceContract proxy = factory.CreateChannel();
try
{
// wait for server to respond
if (host != null && host.State == CommunicationState.Opened)
{
(factory as IContextChannel).OperationTimeout = new TimeSpan(1000);
}
//signal server that a new instance is selected
proxy.Signal();
return true;
}
catch (EndpointNotFoundException e)
{
//return false to indicate this instance is first instance
return false;
}
}
public static void StartService(IServiceContract instance, string channelUri)
{
host = new ServiceHost(instance, new Uri(channelUri));
try
{
host.AddServiceEndpoint
(typeof(IServiceContract), new NetNamedPipeBinding(), new Uri(channelUri));
host.Open();
(instance as Service).LaucnhStartUpWindow();
}
catch (CommunicationException ex)
{
host.Abort();
}
}
}
现在,如果选择另一个实例,“IsInstanceRunning
”将获得指向端点的通道并向第一个实例发出信号。然后,第一个实例执行必要的操作。
发出信号后,第二个实例关闭。因此,始终存在应用程序的单个实例。
历史
- 2009年11月6日:初始版本