views:

1557

answers:

3

I have a written a Windows Service in C#. It is functioning and performing well. I have added a WCF service to the Windows service to enable client applications to connect to the Windows service and obtain stateful information from the Windows service.

I configured the WCF service to be a singleton, so that the same service instance is used to handle all requests from all clients as follows:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

All clients are able to connect and have access to the same stateful information within the WCF service. However, I am running into the following peculiar behavior.

Revised:
I instantiate the WCF service contract within my Windows Service. Any stateful information assigned at the time of instantiation is available to all clients that connect to the service.

However, any stateful information added to the service contract instance later directly from the Windows Service (not by clients) is not visible to clients that connect to the service. It is as if there are two instances of the service contract: One for the Windows Service and one for the clients that connect to the WCF service.

What is the recommended (best) way to instantiate a WCF service and have it be able to access stateful information available within the Windows Service?

+2  A: 

I would recommend doing an end-run around this by holding your state in a static member, so that it doesn't matter whether or not WCF is creating a new instance for each call or reusing one. This solves the problem and simplifies the code.

Steven Sudit
+2  A: 

Why does the WCF service have to have stateful information? Couldn't that be stored in a database and accessed when needed?

WCF does allow Singleton instances for services - but it's usually discouraged to use this, unless you absolutely, positively have to. Typically, it's easier and scales much better if you can store the stateful info in e.g. a database table and let clients access that using a normal, per-call WCF service.

UPDATE:
OK, another idea: you'll always only gonna have a single ServiceHost anyway. If you choose the "per-call" instanciation mode (as recommended by all leading experts), the ServiceHost will allocate a thread pool of worker threads which will then service the incoming requests.

Why does the WCF service need to be a singleton? Couldn't you use "per-call" and still get at the stateful information in the NT Service?

A request comes in and an instance of your service object (the service class, implementing the service interface) is created. How do you access the stateful information in the NT service right now? Couldn't you do that from the newly created service instance, too - when you actually need it?

If you have stateful information being held in the NT Service, you'll need to make sure any concurrent access will be properly handled - that's totally independent of whether your WCF service class is a singleton or not.

UPDATE 2:
Using the 'OperationContext.Current.Host', you can access the ServiceHost that hosts a given service instance inside the service method being executed - not sure if you can access the actual NT service instance. But if you create your own custom ServiceHost descendant, which has an additional property "ListOfClients", you should be able to access that list at any time, from any service instance running.

MIND YOU: since there are possibly any number of service requests being processed at any given time, reading the list must be thread-safe, and updating the list from the Windows NT Service is even more "risky" and needs to take these concurrency issues into account! Lock the list if you need to update it - otherwise, you'll have unpredictable results.

Marc

marc_s
I don't really need the WCF service to be stateful. I have stateful information already within the Windows Service. It is this information that I want the WCF service to be able to provide to to clients that request it. How can I solve this?
Elan
Sure, I could solve this by storing the information to the database. It just seems like unnecessary overhead, when the information is already available within the Windows Service, especially when the WCF service is hosted within the context of the Windows Service. It seems I should not have to now additionally store it and retrieve it from the database to make it accessible to clients. Ideally, I would like the WCF service to provide access to stateful data within the Windows Service.
Elan
To answer your question, I had initially started out assigning a reference to the list to the WCF service host instance, but will now get away from this approach as it does not work aside from requiring a Singleton.
Elan
I get it. I plan to go with "per-call" as I agree this is a better approach. I basically have a stateful list of clients that have discovered the server. What if I made this List<> static within the Windows Service, which the WCF service could access?
Elan
Elan: I think you have a misconception here: the ServiceHost instance will only ever exist as a single instance - there's only ever **ONE** to begin with! That's **NOT** what you're controlling with the InstanceContextMode setting.
marc_s
Thanks for pointing this out. I revised my original question - I should have said "service contract" not "ServiceHost". By actual test, I discovered two instances of my service contract being created: Instance members contained different data when accessed by the Windows Service versus clients connecting to the WCF service.
Elan
+1  A: 

Setting InstanceContextMode.Single will cause the ServiceHost to construct a single instance of your service and use that for all calls. But it sounds like you would like to construct the instance yourself, and populate it with a reference to some shared state. If so, that's called the "well-known instance" pattern and can be accomplished by passing the instance to the ServiceHost constructory, like so:

var svc = new MyServiceClass(state);
var host = new ServiceHost(svc, new Uri(..), ...);
...

ServiceHost will use the instance you pass in for all calls.

An important consideration when using the Single instance mode (whether the object is "well-known" or constructed by the ServiceHost) is threading. By default WCF will only allow one thread to execute concurrently per service instance. So in the PerCall instance mode, since you'll have multiple service instances, you can support multiple concurrent threads which will improve throughput under normal conditions. But with the Single instance mode you only have one service instance so you'd only run one thread at a time. It depends on the service, but it often makes sense then to switch the concurrency mode to Multiple, which will allow multiple concurrent threads into your service instance, but requires that your service implementation be thread-safe.

Some good docs here: http://msdn.microsoft.com/en-us/library/ms731193.aspx

alexdej