我有一个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,不适用于任何客户端。
答案 0 :(得分:1)
只是没有单一实例服务。将所有州迁移到另一个班级,让您的服务成为无国籍。无状态服务可以获取单例实例并使用它。
通过将所有有状态转移到您自己的代码中,您可以控制何时创建实例。你可以强制它被创建。
这是草图:
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 :(得分:0)
首先不要将您自己的单身人士编码为您的设置 InstanceContextMode为服务上的Single。 WCF只会创建一个 为所有请求提供服务。
从其他服务调用wcf服务作为任何其他服务,例如 使用WCF客户端代理。
您不需要为IIS烦恼 是否创建了实例,它将在第一次请求时创建实例。
如果您担心从另一个主叫服务的性能 服务,如果他们在IIS中的同一台机器相同的应用程序, 考虑使用nettcp绑定或net命名管道绑定。
答案 2 :(得分:0)
我坦率地说,我认为你可能有一些设计问题;但是,你所要求的并非不可能。
实施此课程:
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;博士:如果不清楚的话。这是糟糕的设计。