繁体   English   中英

在IIS中访问WCF单例

[英]Accessing the WCF singleton in IIS

我有一个具有instanceContextMode = single的服务(称为MainService )。

我也有另一种服务,这种服务必须跟上述服务的单个实例( 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尚未创建服务实例时才需要此实例)。 这显然是一个令人费解的hack,我想知道是否有正常的方法。

我无法执行常规的单例模式,因为我托管在IIS中,并且IIS不知道如何通过某些函数(例如GetInstance )创建服务实例。

编辑1

我不希望OtherService像其他任何服务一样与MainService进行通信,因为MainService必须将DoSomeFunction定义为服务操作,任何人都可以调用函数DoSomeFunction。 DoSomeFunction适用于OtherService,而不仅仅是任何客户端。

只是没有单一实例服务。 将所有状态移到另一个类中,并使服务变为无状态。 无状态服务可以获取并使用单例实例。

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

这是一个草图:

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应用程序。 您必须假定应用程序随时被杀死(例如,电源故障,崩溃,错误等)。 此外,您需要一个高可用性解决方案,该解决方案通常涉及多次实例化应用程序。

  1. 第一件事不要编写您自己的单例代码,因为您正在将InstanceContextMode设置为on service。 WCF将仅创建一个用于服务所有请求。

  2. 与其他服务一样,从其他服务调用wcf服务,例如使用WCF客户端代理。

  3. 您无需担心IIS是否已创建实例,也可以在首次请求时创建实例。

  4. 如果您担心从另一个服务调用主要服务的性能(如果它们在IIS中的同一应用程序的同一台计算机上),请考虑使用nettcp绑定或网络命名管道绑定。

坦率地说,我认为您可能会遇到一些设计问题; 但是,您要问的并非不可能。

实现这个类:

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;博士:如果不清楚。 这是糟糕的设计。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM