2011-08-01 29 views
8

我会继续前言,并说:我对WCF有点新鲜。WCF服务方法中单例模式的问题

我正在做一个服务器端例程,负责做大量的业务逻辑。它可以通过WCF从客户端访问。

我的主要WCF方法调用其他几个私有方法。我决定使用名为DataProvider的类的单例实例来包含所有这些“查找数据”,而不是将所有“查找数据”传递给每个私有方法的业务逻辑。

在例程结束时,我“释放”DataProvider的查找数据,以便下次执行例程时,将使用最新的查找数据。

所以,这里有一个简单的例子:

public void Generate() 
{ 
     try 
     { 
      //populate singleton DataProvider with it's lookup data... 
      DataProvider.Instance.LoadLookupData(); 

      //do business logic... 
     } 
     finally 
     { 
      //release provider's lookup data... 
      DataProvider.Release(); 
     } 
} 

这个伟大的工程,直到我有一个在(或接近)同时执行该方法的两个不同的客户端。发生问题是因为它们共享相同的单例实例,并且首先完成的任务将在另一个完成之前释放DataProvider。

所以...

我在这里有什么选择?

我想避免传递所有的查找数据,所以单例模式(或一些派生)似乎是一个不错的选择。我还需要能够支持多个客户端同时调用该方法。

我相信WCF服务配置为“Per-Call”。我不确定是否有办法配置WCF服务,以便在服务调用之间不共享静态内存。

任何帮助,将不胜感激。

+1

有人纠正我,如果我在这里错了,但将查找数据传递到另一个类不会创建全部数据的全新副本,对吧?难道它不只是数据参考的副本吗? (当然,除非在服务范围内序列化,否则在这种情况下听起来不太可能) –

+0

我想了解拥有单身人士课程的动机。是否只创建一次,并且您的服务的所有调用者都需要获取相同的数据实例?还是像你的服务返回的调用者应该得到相同的数据(会话)? – Kangkan

+1

“单身人士”的原因是业务逻辑创建了大约30多种不同类型的对象。每个人都需要访问查找数据。也许我很懒,但我不想为30多个不同的构造函数提供相同的参数。大声笑。我觉得单例是最简洁的方法,因此每个对象都可以轻松访问查找数据。 –

回答

8

默认情况下WCF使用“Per-Call”,这意味着为每个客户端的呼叫创建WCF服务的新实例。现在,既然你实现了单例,即使创建了WCF的新实例,它仍然会调用你的单例。

如果您希望为每个调用创建查找(就像您现在所做的那样),您不应该将它作为单例执行。这样每个调用你的方法的客户端都会有新的查询实例,我认为这是你的意图。

但是,如果您的查找速度没有那么快,我建议在所有调用之间共享它,这样可以提高WCF服务的性能。您将需要声明WCF服务作为

InstanceContextMode = InstanceContextMode.Single 
ConcurrencyMode = ConcurrencyMode.Multiple 

这样做是通过WCF创建辛格尔顿自动你,所以你不必自己做,第二个将支持> 1个的并发用户( ConcurrencyMode.Multiple)。

现在,如果你有你的查找正在发生变化,它需要一段时间之后重新加载,我还是会建议使用

InstanceContextMode = InstanceContextMode.Single 
ConcurrencyMode = ConcurrencyMode.Multiple 

但里面在你的代码缓存,然后过期缓存在具体时间或相对时间(1小时)。

这里有一些链接,可以帮助你: 3 ways to do WCF instance management (Per call, Per session and Single)

希望这会有所帮助。

+1

如果您使用在调用之间共享的缓存解决方案,为什么要使用单例实例化模式?看起来使用per-call实例和共享缓存解决方案会更简单,那么您不必担心(尽可能多)关于线程安全性的问题。 –

+0

@Joel C如果您决定执行Per-Call或Single,则无需担心,但仍需要考虑将加载数据同步到缓存。由于缓存将是唯一的一个实例,您需要进行同步。使用Per-Call将为每个客户端创建新的WCF服务实例,并调用后面的缓存数据。现在的问题是为什么需要创建新的WCF实例?没有意义,所以我建议使用Single。由于从缓存中读取日期,您不必执行同步操作,因此它是只读操作。 –

+2

由于'ConcurrencyMode“,我正在谈论更多关于处理WCF服务方法中的同步问题。多个'意味着可以有多个线程同时执行相同的方法。通过每次调用,每个请求都有一个实例,所以当您处理静态变量时,多线程和同步只会成为问题。 –

1

简单的就是用一个同步机制 - 有你看着锁(...) - 这将作为一个看门人很像一个关键部分

(如果你在程序窗口中遇到的那些)在类

static object lockObject = new object(); 

定义静态对象,并用它生成方法

void Generate() 
{ 
    lock(lockObject) 
    { 
    ... 
    } 
} 
+0

我假设你正在寻找共享呼叫之间的数据 - 或者这是每个被调用者,即2个调用者获得不同的数据,但如果再次调用会得到相同的结果 –

+0

这肯定会起作用,但业务逻辑需要几分钟。如果另一个客户端已经在执行,我们不想阻止其他客户端执行逻辑。 –

4

在WCF服务的静态变量总是实例之间共享不管WCF InstanceContextMode setting.的好像你会使用缓存模式为您查找数据会更好。 answers to this caching question提供了一些替代品来滚动你自己的,虽然它们有点过时。此外,如果您决定将整个服务实例设置为单例(InstanceContextMode = Single)是最简单的解决方案,请注意,除非您还使代码成为多线程,否则通常会终止服务可伸缩性(ConcurrencyMode=Multiple)。如果你可以在你的睡眠中淘汰线程安全的代码,那么单身服务可能适合你。