在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服务的,而不是为任何客户端服务。
不要使用单一实例服务。将所有状态移动到不同的类中,使您的服务成为无状态的。无状态服务可以获取单例实例并使用它。
通过将所有有状态性移动到您自己的代码中,您可以控制何时创建实例。可以强制创建。
这里有一个草图:
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等)。此外,您还需要一个高可用性解决方案,这通常涉及到多次实例化应用程序。
-
首先不要像你设置的那样编写你自己的单例InstanceContextMode为单端服务。WCF将只创建一个
-
从其他服务调用wcf service作为任何其他服务,如
-
你不需要麻烦IIS有
-
如果您担心从另一个主服务调用的性能如果它们在同一台机器上,同一应用程序在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:如果不清楚的话。