Problems with singleton pattern inside WCF service method

14,182

Solution 1

By default WCF is using "Per-Call", which means new instance of the WCF service is created for each client's call. Now since you implemented singleton even though new instance of the WCF is created it still calls your singleton.

If you would like to create lookup that is created for each call (like you have now) you should not do it as singleton. This way each client that calls your method will have new instance of the lookup, I think that was your intention.

However if you have lookup that is not changing that fast, I would recommend to share it between all calls, this will improve performance of your WCF service. You will need to declare your WCF service as

InstanceContextMode = InstanceContextMode.Single
ConcurrencyMode = ConcurrencyMode.Multiple  

What this does is creating Singleton automatically for you by WCF, so you don't have to do it yourself, second it will support > 1 concurrent user (ConcurrencyMode.Multiple).

Now if you have your lookup that is changing and it needs to be reloaded after some period of time, I still would recommend using

InstanceContextMode = InstanceContextMode.Single 
ConcurrencyMode = ConcurrencyMode.Multiple

but inside in your code cache it and then expire your cache at specific time or relative time (1 hours).

Here are some links that might help you: 3 ways to do WCF instance management (Per call, Per session and Single)

Hope this will help.

Solution 2

The static variables in a WCF service are always shared between instances regardless of the WCF InstanceContextMode setting. It seems you would be better off using a caching pattern for your look up data. The answers to this caching question provide some alternatives to rolling your own although they are a bit dated.

Also, if you decide that making the whole service instance a singleton (InstanceContextMode=Single) is the easiest solution be aware that you'll generally kill service scalability unless you also make your code multi-threaded (ConcurrencyMode=Multiple). If you can knock out thread-safe code in your sleep then a singleton service might be for you.

Solution 3

simplest is to use a synchronization mechanism - have you looked at lock(...) - this will act as a gatekeeper a lot like a critical section (if you have come across those in windows programming)

define a static object in your class

i.e.

static object lockObject = new object();

and use it in Generate method

i.e.

void Generate()
{
    lock(lockObject)
    {
    ...
    }
}
Share:
14,182

Related videos on Youtube

John Russell
Author by

John Russell

Updated on June 04, 2022

Comments

  • John Russell
    John Russell almost 2 years

    I will go ahead and preface this by saying: I am somewhat new to WCF.

    I'm working on a server-side routine that's responsible for doing a great deal of business logic. It's accessible from a client via WCF.

    My main WCF method calls off to several other private methods. Instead of passing around all of the "lookup data" I need for the business logic to each private method, I decided to use a singleton instance of a class named DataProvider that contains all of this "lookup data".

    At the end of the routine, I "release" the DataProvider's lookup data so the next time the routine is executed, the latest lookup data will be used.

    So, here's a simplified example:

     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();
          }
     }
    

    This works great until I have two different clients that execute the method at (or near) the same time. Problems occur because they share the same singleton instance and the task who finishes first will release the DataProvider before the other completes.

    So...

    What are my options here?

    I'd like to avoid passing around all of the lookup data so the singleton pattern (or some derivative) seems like a good choice. I also need to be able to support multiple clients calling the method at the same time.

    I believe the WCF service is configured as "Per-Call". I'm not sure if there's a way to configure a WCF service so that the static memory is not shared between service invocations.

    Any help would be appreciated.

    • Joel C
      Joel C over 12 years
      Someone correct me if I'm wrong here, but passing the lookup data into another class wouldn't create entirely new copies of all his data, right? Wouldn't it just be a copy of the reference to the data? (Unless of course it's getting serialized across a service boundary, which doesn't sound likely in this case)
    • John Russell
      John Russell over 12 years
      The reason for the "singleton" is that the business logic creates approximately 30+ different types of objects. Each needs access to the lookup data. Perhaps I was being lazy, but I didn't feel like having the same argument to 30+ different constructors. Lol. I felt like singleton was the cleanest approach so that each object could easily access the lookup data.
  • Shaun Wilde
    Shaun Wilde over 12 years
    I've made the assumption that you are looking to share data between calls - or is this per callee i.e. 2 callers get different data but will get the same if the call again
  • Joel C
    Joel C over 12 years
    Why would you use singleton instancing mode if you're using a caching solution that gets shared between calls? It seems like it would be simpler to use per-call instancing and a shared caching solution, then you don't have to worry (as much) about thread-safety concerns.
  • Vlad Bezden
    Vlad Bezden over 12 years
    @Joel C Doesn't matter if you decide to do it Per-Call or Single, you still need to think about synchronization of the loading data to the cache. Since cache will the only one instance and you will need to do synchronization. Using Per-Call will create new WCF service instance for each client and call cached data behind. Now the question is why new WCF instance needs to be created? There is no point for it, that is why I suggested to use Single. Since date read from cache you don't have to do about synchronization, it is read-only operation.
  • Joel C
    Joel C over 12 years
    I was talking more about dealing with synchronization within the WCF service's methods, since ConcurrencyMode.Multiple means there can be multiple threads executing the same method at the same time. With per-call, you have a single instance per request, so multi-threading and synchronization only become issues when you're dealing with static variables.
  • Vlad Bezden
    Vlad Bezden over 12 years
    @Joel Absolutely, for regular method call I would use Per-Call type, but for getting cached data method from WCF I would use Single and ConcurencyMode.Multiple. Is that make sense?
  • Joel C
    Joel C over 12 years
    Except there's more to the service than just returning the cached data, note the part //do business logic...
  • John Russell
    John Russell over 12 years
    This would certainly work, but the business logic takes several minutes. We don't want to block additional clients from executing the logic if another client is already executing.
  • John Russell
    John Russell over 12 years
    Thanks a bunch for the input. Your post led me to the final solution. I left the WCF service as Per Call. However, as far as the "singleton", instead of making it a true static singleton, I simply "attached" it to an extension on the Per Call OperationContext using the technique described here: hyperthink.net/blog/…. Once the WCF call (business logic) is finished. The context and my singleton are dropped. Works great in the multi client scenario too.