在IIS中访问WCF单例

本文关键字:WCF 单例 访问 IIS | 更新日期: 2023-09-27 18:12:46

我有一个服务(叫做MainService),它有instanceContextMode = single

我还有另一个服务,这个服务必须与上述服务的单个实例通信(OtherService调用MainService中的函数)

我决定这样做:

public class OtherService
{
   ...
   MainService.DoSomeFunction();
   ...
}

MainService类中的

public class MainService
{
   private ManualResetEvent manualEventInCtor = new ManualResetEvent(false);
   private static MainService _theInstance = null;
   private static MainService TheInstance
   {
       get
       {
           if(_theInstance == null)
           {
                MainService.IMainContract dummyClient = new MainService.MainContractClient();
                dummyClient.function();
                manualEventInCtor.WaitOne();
           }
           return _theInstance;
       }
       set
       {
           _theInstance = value;
       }
   }
   ...
   public MainService()
   {
       ...
       TheInstance = this;
       manualEventInCtor.set();
       ...
   }
   public static void DoSomeFunction()
   {
       TheInstance.SomeFunction();
   }
   ...
}

我最终不得不让TheInstance getter创建一个对服务的虚拟调用,以便IIS创建实例(只有在服务实例尚未由IIS创建时才需要这样做)。这显然是一个令人费解的黑客,我想知道是否有一个正常的方法。

我不能做一个正常的单例模式,因为我在IIS中托管,IIS不知道如何从一些函数(例如GetInstance)创建服务实例。

编辑1

我不希望OtherService像其他服务一样与MainService对话,因为这样MainService就必须将DoSomeFunction定义为一个服务操作,并且任何人都可以调用DoSomeFunction函数。DoSomeFunction是为OtherService服务的,而不是为任何客户端服务。

在IIS中访问WCF单例

不要使用单一实例服务。将所有状态移动到不同的类中,使您的服务成为无状态的。无状态服务可以获取单例实例并使用它。

通过将所有有状态性移动到您自己的代码中,您可以控制何时创建实例。可以强制创建。

这里有一个草图:

class MySingleton {
 //You can use any lazy initialization logic you like
 //I just used a static initializer as an example
 public static readonly MySingleton Instance = new ...();
 //Move all static data into this class
 //WCF never has to instantiate this class
 //Use it from anywhere you like
}
class MyWcfService {
 //This WCF service has no state
 //Therefore it does not need single instance mode
 //Any instancing mode will do
 //No one except WCF will ever need to use this class
 public void SomeServiceMethod() {
  MySingleton.Instance.DoSomething();
 }
}

这与这个问题无关:要避免有状态的web服务和web应用程序。您必须假设应用程序在任何时候都被终止(例如电源故障、崩溃、bug等)。此外,您还需要一个高可用性解决方案,这通常涉及到多次实例化应用程序。

  1. 首先不要像你设置的那样编写你自己的单例InstanceContextMode为单端服务。WCF将只创建一个

  2. 从其他服务调用wcf service作为任何其他服务,如

  3. 你不需要麻烦IIS有

  4. 如果您担心从另一个主服务调用的性能如果它们在同一台机器上,同一应用程序在IIS中,

我坦率地说,我认为你可能有一些设计问题;然而,你所要求的并不是不可能的。

实现该类:

public static class Singleton<T> where T : new()
{
    public static event EventHandler<SingletonChangedEventArgs> SingletonChangedEvent;
    public static T Instance { get { return instance; } }
    private static T instance = new T();
    public static void SetSingleton(T newInstance)
    {
        T temp = instance;
        instance = newInstance;
        if (SingletonChangedEvent != null)
            SingletonChangedEvent(instance, new SingletonChangedEventArgs { PreviousInstance = temp});
    }
}

还有这个

public class SingletonChangedEventArgs : EventArgs
{
    public object PreviousInstance { get; set; }
}

让你的主服务和其他服务一样,像这样:

[ServiceBehavior( InstanceContextMode = InstanceContextMode.Single)]
public class MyService : IMyService
{
    public MyService()
    {
        //Pay attention to this, the rest of this class is fluff.
        Singleton<MyService>.SetSingleton(this);
    }
    public String Hello(String Name)
    {
        return "Hello " + Name;
    }
    public Person GetPerson()
    {
        return new Person() { Age = 21 };
    }
}

我强烈建议你订阅SingletonChangedEvent,并为单例更改编写逻辑,因为单例的要点是它只能实例化一次,如果你的单例管理一个状态,那么这个状态可以被更改,它可能会有一些主要的影响。

要做到这一点,一个好方法是在任何客户端代码中保持对单例的引用,并订阅事件。如果单例实例的地址与客户端代码的地址不同,客户端代码保持将其更改回来的能力。

这将允许你对你的单例进行单元测试,除了允许你正常运行它之外,还允许你将它作为一个单例使用。

无论如何,如果你想访问你的单例很容易:

Singleton<MyService>.Instance.Hello("Aelphaeis");

我觉得这个解决方案比你现在做的要干净得多;但是,我仍然认为你在设计上有问题,你可能需要考虑改变你的程序结构。

PS/tl;dr:如果不清楚的话。