Building distributed systems using WCF has so many advantages. One of the things I hear consistently from customers is that it allows them to focus their development efforts on writing business logic code and less on having to write “plumbing” code. Still, writing effective services requires that we think about things like service level agreements (SLA) and from a developer’s perspective this often raises questions like…
Under what circumstances should instances of the service be created?
How long should a particular instance exist?
What level of concurrency (single-threaded or multi-threaded) needs to be supported?
What are the scalability requirements for the service?
Does the service need to manage state between calls?
Building services that address these questions are only part of the solution. Informing WCF how our service should be hosted to leverage these implementation details is another. For example, if we’ve built our service such that the operations are multi-threaded, then we will want WCF to host our service differently than if it were a single-threaded service. WCF provides behaviors that we can apply declaratively in our code to customize how our service is hosted. These are InstanceContextMode and ConcurrencyMode and both are applied via the ServiceBehaviorAttribute.
InstanceContextMode determines when an instance of your service is created and for how long it will exist. Your choices are PerCall, PerSession, or Single. A common question I hear often is: “Why would you ever want to use PerCall instancing and incur the overhead of creating a service for every message?” For which I usually reply: “What overhead?”. True, a new instance of your service class is recreated for every message. However, that equates to just creating an instance of a class. Unless your service class has some expensive initialization code in the constructor (for example, querying a database or building large object graphs in memory), the PerCall instancing model is very efficient. The overhead of building up the Channel layer (for example, listening on endpoints) and Service Model layer (for example, applying behaviors to customize the runtime) occurs one time for each ServiceHost instance. The following diagram illustrates this idea.
So, when would you choose one instancing mode over another? That depends on the requirements for your service. However, here are some (not all) common things to consider.
You may consider this instancing mode in these circumstances.
- If your service is stateless
- If your service has light-weight initialization code (or none at all).
- If your service is single threaded.
- If your service needs to maintain some state between calls from the same client.
- If your service has light-weight initialization code (or none at all). Even though you are only getting a new instance for each client proxy, you still want to be careful about having expensive initialization code in a constructor.
By default, WCF will use PerSession provided the client and service are communicating over a binding that supports session. Otherwise, the service will behave as a PerCall service. Which raises the question: How can a developer place a constraint on the service such that the service’s endpoints support sessions? The answer is in the ServiceContractAttribute.SessionMode property that can be applied to your service contract. Using this property you can “require” sessions for your service. If any endpoints configured for your service don’t support session then the service will fail to start. This is your way, as a developer, to place a constraint on the administrator, to configure your service with endpoints that support your requirements (sessions in this case). Be advised that there are 4 different types of sessions in WCF and setting this property requires only that the binding support one of these types of session. It does not let you define the type of session you require.
- If your service needs to maintain some state between clients.
- Your service has expensive initialization code. That is, initializing for every client (PerSession) or every call (PerCall) would be too costly.
- You don’t anticipate needing to scale out your service.
If your service will be deployed in a server farm, then be sure to review the WCF Load Balancing guidance for scenarios that may apply to your service.
In the next posting, I will say a few things about Concurrency.