65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 单实例

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.29/5 (3投票s)

2009年11月6日

CPOL

2分钟阅读

viewsIcon

38148

downloadIcon

549

WCF 如何用于创建应用程序的单个实例

引言

有些应用程序希望在任何时候只有一个实例在运行。     

要创建一个单实例应用程序,需要满足两个条件:

  1. 应用程序应该能够识别自身是否已经有实例在运行。
  2. 如果是,则通知第一个实例,并让第一个实例来处理这种情况。

由于这两个实例是完全不同的进程,因此涉及到进程间通信。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日:初始版本
© . All rights reserved.