WCF helps you build your SOA or simply eases the way of connecting two applications. To handle this, the connection of the client and the service needs to be handled in some way. The good thing about WCF is that it is so very extendable and configurable. This holds true for the management of client and service connection and instances of the service.

To manage the lifecycle of the service instance, WCF has different modes how it binds single client requests to the instance of a service. This is necessary, because for service oriented applications the needs for scalability, performance, throughput, durability, transactions and so on differ quite a much. So as with the bindings, there are a lot of permutations of this. The three modes WCF provides you with can be customized further and are the following:

  1. Per Call service. Essentially allocate and destroy a service instance for each client request
  2. Per Session service. Each client that connects gets a service instance until it closes the connection.
  3. Singleton service. One service for all the clients that might connect.

We will look into the rationale behind all of those three instance modes and how to specify them.

What this post will cover

  • The three InstanceContextModes
  • How to set up each Service instance mode
  • When to use which and specifics of each service

What this post will not cover

  • What an InstanceContext is
  • How behaviors work in WCF and how they are extendable

Are there alternatives

  • No. To configure Services for different scenarios you will need to use ServiceBehaviors, either the ones specified or you have to implement your own (see Behavior and Extension of WCF)

As reference we use the following ServiceContract in this post:

[ServiceContract(Name="myservice", Namespace="contextmodes")]
public interface IMyService
{
[OperationContract]
void MyMethod();
}

ServiceBehavior and the InstanceContextMode

The instance management is actually an implementation detail of the service contract. And because we always want to hide the implementation details of the service from the client as much as possible, this will only be applied on the implementing class of the ServiceContract. This can be done programmatically (which I do prefer) and administratively. To accomplish this, WCF offers you the ServiceBehaviorAttribute.

The instance lifecycle of a service is controlled with the InstanceContextMode enum property of the ServiceBehaviorAttribute.

public enum InstanceContextMode
{
PerCall,
PerSession,
Single
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
{
public InstanceContextMode InstanceContextMode { get; set;}
// other members omitted
}

 

The enum is aptly named InstanceContextMode, because it controls the hosting environment (aka context) as well as the instance that is hosted in this context. The members of the enum point to the three possible modes how a service can be run against client requests. We will now in the upcoming sections walk through each and explore what they do individually, how to set up a given Mode and when to use which mode. We’ll start with Per Call Services.

Per Call Services

The InstanceContextMode of per call simply means, that each client REQUEST gets a new dedicated service instance. In effect this means each method call invocation on a proxy will instantiate a new service instance and terminate it with the return of the call.

General workflow:

  1. client creates proxy.
  2. proxy calls method on per call service
  3. method call returns, WCF calls IDisposable.Dispose() on the service instance and destroys the Context.

If your service implementation implements the IDisposable interface, WCF will automatically call it, lets your service clean up, and make the instance and context eligible for garbage collection.

Advantages of Per Call

If you configure your service for per call, the main benefit you will get and most likely seek after is scalability. This is because you can allocate memory only for the briefest moment it is needed on the service side. This obviously isn’t free to get (what is actually?) so we explore this further in the section about design considerations. Yet if your service needs to scale as the main objective, then the per call service is the way to go. Actually it might be the most desired behavior for any service.

The way each request allocates the resources on demand works also well with the transactional model that is needed for lots of applications.
Also the way you need to design per call services, they do map very nicely to queued or disconnected services.

Disadvantages and Design considerations

With this sort of programming model come some extra design decisions you need to have as a service developer.
The most common scenario because of this allocation for each client request, is that you load some state at the start of the call, do some work and then save the state back to storage. The issue is that you need a way to somehow associate the client with the new instance to give the impression of a continuous session. This cries for an extra parameter that somehow identifies the state of the caller.

This is not exactly hiding the implementation details. Yet there is no other solution, if your service would be stateless and there would be no state handled from the service on behalf of the client, you would probably have no need for the per call service in the first place.

Another issue with per call services is that allocation of resources combined with load, do work, save cycle obviously impacts the performance of the service. Also you can save the state in some volatile storage, or in a database not everything can be serialized. The things like database connections, file streams etc. need to be allocated at each call. So in essence you trade performance of the service for scalability.
With this considerations in mind we will now look at the way a per call service is created:

First we need to adjust the MyService Contract for the aforementioned stateidentifying parameter:

public interface IMyService
{
[OperationContract]
void MyMethod(ParameterObject stateIdentifier);
}

Next we need to specify the InstanceContextMode on the ServiceBehavior for the IMPLEMENTATION of the service.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService
{
public void MyMethod(ParameterObject stateIdentifier)
{
var state = GetState(stateIdentifier);
DoWork(state);
SaveState(state, stateIdentifier);
}
private StateObject GetState(ParameterObject stateIdentifier)
{ /* load state from storage*/ }
private void SaveState(ParameterObject stateIdentifier, StateObject state)
{ /* save state to storage */}
}

I used generic state and parameter objects, because their implementation does not matter, I just wanted to convey the idea.

You can tell by the nature of the per call service, that it is best if the method call only is used to do a finite amount of work and does not spin up background threads because this would not work well with the gestate/dowork/loadstate cycle and also does not work well with the termination at method call return.

One other thing to take into consideration is, that not every programmer is familiar with this kind of programming model, so besides the performance penalties you might pay for a steeper learning curve.

When to use Per Call Services

Advertantly to the client server model, the per call service works well for service orientation. This is mostly due to the scaling possibilities you get with this services. You will want to use Per Call if you have a situation where you cannot accurately predict the future load. So you could design a per call service as sort of a safety factor for future load. As we have seen it is actually best to start with per call services, because you can always use another mode with the parameter to identify state, but adding the parameter later would break client code.

Per Session

The per session mode is the default mode of WCF InstanceContextMode and works like the classic client/server model. This means each client gets a dedicatied service instance for the client (session per endpoint per proxy). The session is created when the proxy of the client is used for the first invocation. Essentially if the same client connects to the same endpoint a second time, it gets a new dedicated service instance for all operations and channels associated with the context of the service. The session is terminated when the client closes the proxy/channel that was initially used for the session.
This session is only a logical session, the way WCF functions still applies (roughly speaking: client forwards call to proxy, which in turn uses the message channels to invoke a remote method via SOAP)

Setup a sessionful services

Because this is actually the default service behavior, there is no configuration needed. But I personally would state the InstanceContextMode because it is more explicit that way. As with the Per Call service we need to look closer at the details of the sessionful service to understand when to use it best.
To aid WCF with supporting a session, WCF needs to know how to associate a client with a given instance. For this you need to utilize the SessionMode enum:

public enum SessionMode
{
Allowed,
Required,
NotAllowed
}

SessionMode.Allowed

The is the default mode . The SessionMode and the Binding together depict how the server behaves. For example the SessionMode.Allowed and HttpBinding with an InstanceContextMode.PerSession do not work due to the connectionless nature of http. Interestingly enough the service will then behave like a per call service, even though it is configured for another purpose. If you use NetTcpBinding or NetNamedPipesBinding (or WSHttpBinding with Message security) a Per Session Service is created.

SessionMode.Required

If you use this session mode you cannot use a Binding that does not have a transport-level session, or else the service will throw an exception at load time. So you cannot use http for this kind of service. Because this again is just an implementation detail, you can apply this session mode without problem on a use of Per Call Services (even with http).
If you design a sessionful service always apply the SessionMode.Required to be as explicit as possible.

SessionMode.NotAllowed

With no regard to the InstanceContextMode, the service configured with this SessionMode will always behave like a Per Call service. Since TCP and IPC both maintain a transport session you cannot use services with endpoints that use SessionMode.NotAllowed and those protocols. This is ensured at service load time.
This mode does not do much useful with respect to the other two modes, and I guess the makers of WCF only included it for completeness sake.

Sessions and reliability

Because a session can only be as reliable as its transport session, you will want to employ a contract that uses endpoints with reliable transport sessions. For TCP you will need to set the reliable session property to true (set the property of the NetTcpBinding or configure a Binding section on app.config level). For IPC this is not needed, because WCF only allows IPC on the same machine and that has transport session built into it.

Session ID

The OperationContext of each session has a property Session ID. This unique id (this is null on Per Call services) can be accessed form the service as well as from the client (via the proxy). Yet there are some pitfalls to consider. The client should only get hold of the sessionid after establishing the connection to the proxy. Else the ID could potentially not match to the one of the service. Better yet is if the client waits after the first call has returned. This can be ensured by some sort of connection method. How you would go about this look at my Callback example, there I set up a service that needs to use a connect and disconnect method.

Sessionful Service more fine grained configuration

The sessionful service connects a client to the service instance. Yet due to the nature of SOAP, this is not the full picture. The clients will not be correlated to the instance, but rather to the context in which they are hosted.
So the default behavior is that the used proxy and channel activate the hosting of a context at session start (first call to service of the proxy that is). With the closing of the channel/proxy the session gets terminated and also closes the context and instance of the service. This default mode can be adjusted to get different behaviors. To manage this you utilize the following enum:

public enum ReleaseInstanceMode
{
None,
BeforeCall,
AfterCall
BeforeAndAfterCall
}

This enum can be set from the OperationBehaviorAttribute that is applied to the given operation.

The enum values for releasing the instance from the context are in relation to the method call from the client. This technique obviously makes most sense to apply sporadically or else you could simply use a per call service instead.

ReleaseInstanceModes

The default is ReleaseInstanceMode.None, this means that there is no difference between the lifecycle of the context and the instance. This is what I described above.

On ReleaseInstanceMode.BeforeCall the forwarded call from WCF checks if there is an instance of the service, deactivates it and creates a new instance before the call is invoked on the service. BeforeCall makes sense for something like Connect() methods or anything that uses expensive resources like database connections or such. If you have then other methods for the session you can call them with the same instance and only allocate the needed memory on demand.

The ReleaseInstanceMode.AfterCall deactivates the instance after the call took place. This can be used for a Disconnect() or Cleanup() style method to terminate the instance without waiting for the session to terminate.

ReleaseInstanceMode.BeforeAndAfterCall combines the two effects of BeforeCall and AfterCall. This means the instance is created for each call of this method, just before the call is invoked, and is terminated just after the call has finished. You can use this to fully emulate a Per Call Service with its state awareness and the low memory footprint compared to a standard sessionful service call.

You might ask why use this enum instead of a per call service? The good thing about this activation mode (or rather a deactivation mode) is that you separate the lifecycle of the context and the service instance. This is different to the per call service, because there you would also get a new context on each request. The sessionful service has a single context for the full session. So you can utilize the session Id and do not need to use a dedicated parameter to identify the associated state.

Another way to deactivate the instance at the end of each call is to call the ReleaseServiceInstance() method on the OperationContext of the service context. This has the same effect as the ReleaseInstanceMode.AfterCall, yet instead of deciding to apply this at design time you can do this programmatically.

Why use this technique

Because this technique is an optimization technique and also an implementation detail of the service (remember behaviors) you would want to avoid it in the general case. This is because it adds complexity and makes it much less maintainable. It is also not the standard knowledge body for use of WCF and may make it harder for others to work with. If you can tell by measuring that it really helps and is better to use a sessionful service than a per call services, you can apply this technique, but in most cases I would avoid it and use a per call service instead.

Advantages and disadvantages of sessionful service

The advantages of a sessionful service are the ease of state association, and that all state can be handled in memory, which makes for good call performance (but maybe not memory wise). Is it also highly configureable even though this might be not the standard body of knowledge for WCF.

Because it maps pretty exactly to the client server model, you get the exact same problems as the client and server model, that is scalability and the transactional problems the client and server bring with them.

Singleton Service

The last of the three modes is the singleton service. This amounts to the ultimate shareable service, because it is created at the start of the service host and life as long as the hosting application. So it does not get closed when any client proxy is closed.
Because it is not the default behavior you need to apply the InstanceContextMode.Single on the servicebehaviorattribute.

Every client is connected to the same context and instance of the service. This has several implications:

  • you need to synchronize the access for concurrent calls
  • only self hosting is applicable for singleton services
  • no logical session is required
  • no transport level session is required (context and instance are unchanged)

Setup a Singleton service

You can setup a singleton service by creating the instance yourself and just add it to the ServiceHost constructor. If you choose this way of initializing a singleton service you might want to access the service instance and this is also possible. For this you use the SingletonInstance property of the ServiceHost.

public class ServiceHost : ServiceHostBase
{
public ServiceHost(object singletonInstance, params Uri[] baseAddresses);
public object SingletonInstance {get;set;}
}

Why choose a Singleton

As you probably can tell the singleton is the sworn enemy of scalability, for one reason because you hold all the needed resources directly in memory (or have significant overhead and complexity in your implementation). Another reason is that you need to synchronize access to state in terms of concurrent calls.

So you probably should only apply a Singleton service if it maps eloquently to a natural singleton, e.g. a global logging service or such. The cases are few, and generally you should consider a per session or per call service.

A case where I build a singleton service was for IPC of an WPF application with a CLI process that traced the doings of the WPF app that where quite complex. Also this communication allowed for the control of the WPF application via CLI commands. Because this was only for developers or support to use and on every machine there actually could only be one such connection it made sense to use the simplest programming model which in this case was the Singleton.

General recommendations

If you use several services it is best to use the same Behavior on most of your services. The bare minimum is that calls that are semantically dependent (which probably should be avoided in the first place) should never use different InstanceContextModes, because the designs for the different services do not really work as complementaries.

Summary

In this post we explored the three instance management modes that WCF supplies and how they can be configured as well as in which context you might consider using them.

The three available modes are Per Call, Per Session and Singleton services. The Per Call creates a new context and instance of the service for each call from the proxy to the service. Per Session manages a logical session for the client and service. This means a session is created for the open method of the proxy and is terminated for the closing of this proxy. If a client would open another proxy a whole new session would be created. We also saw how a so called sessionful service can be configured to separate the context from the service instance to boost performance. The last of the three modes, the singleton, is the ultimative shareable service and certainly has its use cases, but is also the sworn enemy of scalability, which might be an important factor of a service oriented solution.


0 Comments

Leave a Reply

Avatar placeholder