Instance Deactivation

The sessionful service instance management technique as described so far connects a client (or clients) to a service instance. Yet, the real picture is more complex. Recall from Chapter 1 that each service instance is hosted in a context, as shown in Figure 4-2.

Contexts and instances

Figure 4-2. Contexts and instances

What sessions actually do is correlate the client messages not to the instance, but to the context that hosts it. When the session starts, the host creates a new context. When the session ends, the context is terminated. By default, the lifetime of the context is the same as that of the instance it hosts. However, for optimization and extensibility purposes, WCF provides the service designer with the option of separating the two lifetimes and deactivating the instance separately from its context. In fact, WCF also allows a context to exist without an associated instance at all, as shown in Figure 4-2. I call this instance management technique context deactivation. The common way of controlling context deactivation is via the ReleaseInstanceMode property of the OperationBehavior attribute:

public enum ReleaseInstanceMode
{
   None,
   BeforeCall,
   AfterCall,
   BeforeAndAfterCall,
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class OperationBehaviorAttribute : Attribute,...
{
   public ReleaseInstanceMode ReleaseInstanceMode
   {get;set;}
   //More members
}

ReleaseInstanceMode is of the enum type ReleaseInstanceMode. The various values of ReleaseInstanceMode control when to release the instance in relation to the method call: before, after, before and after, or not at all. When releasing the instance, if the service supports IDisposable, the Dispose( ) method is called and Dispose( ) has an operation context.

You typically apply instance deactivation on some but not all service methods, or with different values on different methods:

[ServiceContract(SessionMode = SessionMode.Required)]
interface IMyContract
{
   [OperationContract]
   void MyMethod(  );

   [OperationContract]
   void MyOtherMethod(  );
}
class MyService : IMyContract,IDisposable
{
   [OperationBehavior(ReleaseInstanceMode = ReleaseInstanceMode.AfterCall)]
   public void MyMethod(  )
   {...}
   public void MyOtherMethod(  )
   {...}
   public void Dispose(  )
   {...}
}

The reason you typically apply it sporadically is that if you were to apply it uniformly you would end up with a per-call-like service, in which case you might as well have configured the service as per-call.

If relying on instance deactivation assumes a certain call order, you can try to enforce that order using demarcating operations.

Configuring with ReleaseInstanceMode.None

The default value for the ReleaseInstanceMode property is ReleaseInstanceMode.None, so these two definitions are equivalent:

[OperationBehavior(ReleaseInstanceMode = ReleaseInstanceMode.None)]
public void MyMethod(  )
{...}

public void MyMethod(  )
{...}

ReleaseInstanceMode.None means that the instance lifetime is not affected by the call, as shown in Figure 4-3.

Instance lifetime with methods configured with ReleaseInstanceMode.None

Figure 4-3. Instance lifetime with methods configured with ReleaseInstanceMode.None

Configuring with ReleaseInstanceMode.BeforeCall

When a method is configured with ReleaseInstanceMode.BeforeCall, if there is already an instance in the session, before forwarding the call WCF will deactivate it, create a new instance in its place, and let that new instance service the call, as shown in Figure 4-4.

Instance lifetime with methods configured with ReleaseInstanceMode.BeforeCall

Figure 4-4. Instance lifetime with methods configured with ReleaseInstanceMode.BeforeCall

WCF deactivates the instance and calls Dispose( ) before the call is done on the incoming call thread, while the client blocks. This ensures that the deactivation is indeed done before the call, not concurrently with it. ReleaseInstanceMode.BeforeCall is designed to optimize methods such as Create( ) that acquire some valuable resources, yet wish to release the previously allocated resources. Instead of acquiring the resources when the session starts, you wait until the call to the Create( ) method and then both release the previously allocated resources and allocate new ones. After Create( ) is called, you are ready to start calling other methods on the instance, which are typically configured with ReleaseInstanceMode.None.

Configuring with ReleaseInstanceMode.AfterCall

When a method is configured with ReleaseInstanceMode.AfterCall, WCF deactivates the instance after the call, as shown in Figure 4-5.

Instance lifetime with methods configured with ReleaseInstanceMode.AfterCall

Figure 4-5. Instance lifetime with methods configured with ReleaseInstanceMode.AfterCall

This is designed to optimize a method such as Cleanup( ) that cleans up valuable resources held by the instance, without waiting for the session to terminate. ReleaseInstanceMode.AfterCall is typically applied on methods called after methods configured with ReleaseInstanceMode.None.

Configuring with ReleaseInstanceMode.BeforeAndAfterCall

As its name implies, configuring a method with ReleaseInstanceMode.BeforeAndAfterCall has the combined effect of using ReleaseInstanceMode.BeforeCall and ReleaseInstanceMode.AfterCall. If the context has an instance before the call is made, just before the call WCF deactivates that instance and creates a new instance to service the call. It then deactivates the new instance after the call, as shown in Figure 4-6.

Instance lifetime with methods configured with ReleaseInstanceMode.BeforeAndAfterCall

Figure 4-6. Instance lifetime with methods configured with ReleaseInstanceMode.BeforeAndAfterCall

ReleaseInstanceMode.BeforeAndAfterCall may look superfluous at first glance, but it actually complements the other values. It is designed to be applied on methods called after methods marked with ReleaseInstanceMode.BeforeCall or None, or before methods marked with ReleaseInstanceMode.AfterCall or None. Consider a situation where the sessionful service wants to benefit from state-aware behavior (like a per-call service), while holding onto resources only when needed to optimize resource allocation and security lookup. If ReleaseInstanceMode.BeforeCall were the only available option, there would be a period of time after the call when the resources would still be allocated to the object, but would not be in use. A similar situation would occur if ReleaseInstanceMode.AfterCall were the only available option, because there would be a period of time before the call when the resources would be wasted.

Explicit Deactivation

Instead of making a design-time decision on which methods to use to deactivate an instance, you can make a runtime decision to deactivate the instance after the method returns. You do that by calling the ReleaseServiceInstance( ) method on the instance context. You obtain the instance context via the InstanceContext property of the operation context:

public sealed class InstanceContext : ...
{
   public void ReleaseServiceInstance(  );
   //More members
}
public sealed class OperationContext : ...
{
   public InstanceContext InstanceContext
   {get;}
   //More members
}

Example 4-8 demonstrates this technique.

Example 4-8. Using ReleaseServiceInstance( )

[ServiceContract(SessionMode = SessionMode.Required)]
interface IMyContract
{
   [OperationContract]
   void MyMethod(  );
}
class MyService : IMyContract,IDisposable
{
   public void MyMethod(  )
   {
      //Do some work then
      OperationContext.Current.InstanceContext.ReleaseServiceInstance(  )
;
   }
   public void Dispose(  )
   {...}
}

Calling ReleaseServiceInstance( ) has a similar effect to using ReleaseInstanceMode.AfterCall. When used in a method decorated with ReleaseInstanceMode.BeforeCall, it has a similar effect to using ReleaseInstanceMode.BeforeAndAfterCall.

Tip

Instance deactivation affects a singleton as well, although combining the two makes little sense—by its very definition, it is permissible and even desirable to never deactivate the singleton.

Using Instance Deactivation

Instance deactivation is an optimization technique, and like all optimization techniques, you should avoid it in the general case. Consider using instance deactivation only after failing to meet both your performance and scalability goals and when careful examination and profiling has proven beyond a doubt that using instance deactivation will improve the situation. If scalability and throughput are your concerns, you should take advantage of the simplicity of the per-call instancing mode and avoid instance deactivation. The main reason I share this technique with you is that WCF itself makes extensive use of instance deactivation; thus, knowledge of it is instrumental in demystifying other aspects of WCF, such as durable services and transactions.

Get Programming WCF Services, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.