This column explores the instancing and throttling options for WCF services as it relates to Web service configurations. In "IIS and WAS Hosting Architecture ," I talked about hosting architectures for your WCF services. In this installment, I m going to talk about the features that control the lifetime of individual service instances allocated as messages are processed, as well as their relevance in Web service deployments. For more information on WCF services, see " Security Practices for WCF " and " Going Mobile with WCF ."

 

Instancing Modes

WCF services can be configured such that the lifetime of the service instance is limited to the duration of the request, for the duration of a client session (proxy instance), or forever (in the case of singleton services). The choice of optimal service lifetime may vary by application depending on the expected calling pattern of clients, requirements for state-awareness, and the expected throughput necessary to serve requests.

Instancing modes in WCF control the way that service objects are allocated to handle requests. Requests to each service endpoint are processed by the appropriate service object based on the instancing mode for the service type. Instancing modes are based on the InstanceContextMode enumeration from the System.ServiceModel namespace:

  • PerCall: A new service object is created for each call to the service.
  • PerSession: A new service object is created for each client. This is the default behavior.
  • Single: A single service object is created for all calls from all clients.

You can use ServiceBehaviorAttribute to set InstanceContextMode for a service type. For example, the following shows how to configure the service type as a PerCall service (this setting controls the lifetime of each service object):

[ServiceBehavior(InstanceContextMode=

 InstanceContextMode.PerCall)]

public class PerCallService :IPerCallService

 

PerCall Services

In a typical Web service scenario, when clients invoke a service, they expect only to call a single operation without maintaining state in memory between calls state is usually persisted in the database. For this reason, you ll likely use PerCall services for your Web service implementations of WCF.

As I mentioned, to achieve this with WCF, services are configured for PerCall instancing mode by applying the following service behavior to the service implementation:

[ServiceBehavior(InstanceContextMode=

 InstanceContextMode.PerCall)]

public class PerCallService:IPerCallService

The lifecycle of a PerCall request is as follows:

  • Clients create a proxy instance to invoke the service.
  • Calls to each service operation dispatch messages to the service.
  • A new instance of the service type is constructed for each call, even if calls are issued by the same client proxy.
  • The service type is disposed by the service model when the call has completed.

The allocation of service objects for PerCall services is illustrated in Figure 1. Despite the potential for many service objects being created for multiple concurrent calls, this instancing mode yields the best overall throughput (for several reasons):

  • Because state is not maintained in memory between calls, service types aren t likely to have a heavy constructor initializing other objects.
  • By freeing unused service objects and resources consumed by the service for a single operation, overall memory consumption at the server is reduced. Other instancing modes retain service objects and other state-related objects, even while clients are inactive for some period.
  • Because a new object is allocated for each call, concurrency issues are not a concern at the service layer. However, other objects or resources shared by each service object still require protection for concurrent access.


Figure 1: PerCall services allocate an object for every call.

Operations still construct the necessary business and data access objects to complete their work. These objects, like the service object, usually do not maintain in memory state between calls and are released with the completion of each service operation, as illustrated in Figure 2.

 
Figure 2: Allocation of objects for each service operation.

 

PerSession Services

There are four types of sessions supported by WCF services: application, transport, reliable, and secure. An application session refers to a session in the classic sense of client-server communications. In WCF terms, this means that service objects are kept alive for subsequent calls by the same client proxy until a timeout period has elapsed. A transport session can be a named pipes session or a TCP session. A reliable session provides delivery guarantees and message correlation so that calls from the same client proxy can survive transient network interruptions, so that those calls can be optionally delivered to the service object in the order they were sent. Unlike application sessions, reliable sessions do not send requests to the same service object the session is maintained by the service model. A secure session makes it possible for a client proxy to call service operations without re-authenticating each time. In this case, the channel layer relies on a security context token to reconstruct the security context with the identity of the caller. Once again, secure sessions do not require the same service object to handle requests. This section will focus only on application sessions.

Figure 3 illustrates that service objects are kept alive to handle requests from the same client proxy, for the duration of a session. To enable sessions for a service type, you apply the ServiceBehaviorAttribute and configure its instancing mode to PerSession, as shown here:

[ServiceBehavior(InstanceContextMode=

 InstanceContextMode.PerSession)]

public class PerSessionService:IPerSessionService

This is the default behavior, which means that, by default, service objects are kept alive for the duration of a client session when a binding that supports sessions has been configured. In the case of Web service bindings, BasicHttpBinding does not support sessions. WSHttpBinding and WSFederationHttpBinding support sessions only when reliable sessions or secure sessions are enabled and secure sessions are enabled by default for both bindings. If you disable both reliable sessions and secure sessions, application sessions cannot be supported.


Figure 3: PerSession services allocate a service object for each client.

The lifecycle of a PerSession request is as follows:

  • Clients create a proxy instance to invoke the service.
  • Calls to each service operation dispatch messages to the service.
  • A new instance of the service type is constructed for the first call from the client proxy, and kept alive for subsequent calls from the same client proxy.
  • If the client is inactive for some duration beyond the session timeout, which defaults to 10 minutes, the service instance is disposed.

Because each client gets the same service object for the duration of its session, the service object can hold references to state-aware business objects that live for the duration of the session, as shown in Figure 4. Another alternative could be to maintain tangential state information in the service object, while allowing each request to construct its own business objects for operation calls, as shown in Figure 5. The main distinction between these two approaches is in which objects require protection against concurrent access within a session, and in how much memory is consumed while sessions are alive.


Figure 4: Using state-aware business objects per session.


Figure 5: Using state-unaware business objects per session.

Web services and application sessions typically do not mix. Instead, each operation retrieves state from a data store and saves state back to that store, before completing the operation.

 

Singleton Services

When a WCF service is configured to be a singleton, the same service instance is used to handle all requests from all clients. The instancing mode in this case is set to Single, as shown here:

[ServiceBehavior(InstanceContextMode=

 InstanceContextMode.Single)]

public class SingletonService:ISingletonService

In this case, the service instance is created when the ServiceHost is constructed, and lives until the ServiceHost is closed, or until the application domain is unloaded when the host process is shut down.

Because a singleton service object is shared across all client requests, it is really up to the singleton to determine how its state is managed across those requests. By definition, any references to business objects held by the singleton will be shared by all requests, as shown in Figure 6.


Figure 6: Business objects shared by all requests.

By design, singletons handle all requests from all clients, which is a very real scalability concern for any server deployment. Even if you configure a singleton to allow multiple concurrent requests, any shared resources must be protected from concurrent access. If resource locks are poorly implemented, the same scalability concerns exist as if the singleton allowed only one request to process at a given time. For this reason, you ll probably never configure your Web services as singletons.

 

Conclusion

The important thing to take away from this discussion is that Web services are typically best configured as PerCall services for scalability. Because PerSession is the default, and because WSHttpBinding (a popular Web service binding) has secure sessions enabled by default, you may not realize your services are being treated as PerSession services in the absence of an explicit InstancingMode setting. Thus, it is always best to explicitly set InstancingMode to make it clear to other developers what the expected behavior of the service will be. The only case where PerSession may be useful is where you are not able to store session in a durable store, such as a database, and have considered the scalability and concurrency implications. Singletons are, by and large, not useful in Web service implementations, and should be avoided.

For examples of instancing mode configurations discussed in this article, see sample code for Chapter 5 of Michele s book, Learning WCF.

 

Additional Resources

 

Michele Leroux Bustamante is Chief Architect at IDesign Inc., Microsoft Regional Director for San Diego, Microsoft MVP for Connected Systems, and a BEA Technical Director. At IDesign Michele provides training, mentoring, and high-end architecture consulting services, specializing in scalable and secure .NET architecture design, globalization, Web services, and interoperability with Java platforms. She is a board member for the International Association of Software Architects (IASA), a frequent conference presenter, conference chair of SD s Web Services and Web Development tracks, and a frequently published author. Michele recently completed the book, Learning WCF, published by O Reilly (book blog: http://www.thatindigogirl.com). Reach her at http://www.idesign.net or http://www.dasblonde.net.