Sometimes, a sessionful contract has an implied order to operation invocations. Some operations cannot be called first, while other operations must be called last. For example, consider this contract used to manage customer orders:
[ServiceContract(SessionMode = SessionMode.Required)] interface IOrderManager { [OperationContract] void SetCustomerId(int customerId); [OperationContract] void AddItem(int itemId); [OperationContract] decimal GetTotal( ); [OperationContract] bool ProcessOrders( ); }
The contract has the following constraints: the client must provide the customer ID as the first operation in the session, or else no other operations can take place; items may be added, and the total calculated, in any order, and as often as the client wishes; processing the order terminates the session, and therefore must come last.
WCF allows contract designers to designate contract operations as operations that can or cannot start or terminate the session using the IsInitiating
and IsTerminating
properties of the OperationContract
attribute:
[AttributeUsage(AttributeTargets.Method)] public sealed class OperationContractAttribute : Attribute { public bool IsInitiating {get;set;} public bool IsTerminating {get;set;} //More members }
Using these properties may demarcate the boundary of the session; hence I call this technique demarcating operations. During the service load time (or the proxy use time on the client side), if these properties are set to their nondefault values, WCF verifies that the demarcating operations are part of a contract that mandates sessions (SessionMode
is set to SessionMode.Required
), and will throw an InvalidOperationException
otherwise. Both a sessionful service and a singleton can implement a contract that uses demarcating operations to manage their client sessions.
The default values of these properties are IsInitiating
set to true
and IsTerminating
set to false
. Consequently these two definitions are equivalent:
[ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract { [OperationContract] void MyMethod( ); } [ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract { [OperationContract(IsInitiating =true
,IsTerminating =false
)] void MyMethod( ); }
As you can see, you can set both properties on the same method. In addition, operations do not demarcate the session boundary by default—operations can be called first, last, or in between any other operation in the session. Using nondefault values enables you to dictate that a method is not called first, or that it is called last, or both:
[ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract { [OperationContract] void StartSession( ); [OperationContract(IsInitiating = false)] void CannotStart( ); [OperationContract(IsTerminating = true)] void EndSession( ); [OperationContract(IsInitiating = false,IsTerminating = true)] void CannotStartCanEndSession( ); }
Going back to the order management contract, you can use demarcating operations to enforce the interaction constraints:
[ServiceContract(SessionMode = SessionMode.Required)] interface IOrderManager { [OperationContract] void SetCustomerId(int customerId); [OperationContract(IsInitiating = false)] void AddItem(int itemId); [OperationContract(IsInitiating = false)] decimal GetTotal( ); [OperationContract(IsInitiating = false,IsTerminating = true)] bool ProcessOrders( ); } //Client code OrderManagerClient proxy = new OrderManagerClient( ); proxy.SetCustomerId(123); proxy.AddItem(4); proxy.AddItem(5); proxy.AddItem(6); proxy.ProcessOrders( ); proxy.Close( );
When IsInitiating
is set to true
(its default) it means the operation will start a new session if it is the first method called by the client, but that it will be part of the on-going session if another operation is called first. When IsInitiating
is set to false
, it means that the operation can never be called as the first operation by client in a new session, and that the method can only be part of an ongoing session.
When IsTerminating
is set to false
(its default), it means the session continues after the operation returns. When IsTerminating
is set to true
, it means the session terminates once the method returns, and WCF disposes of the service instance asynchronously. The client will not be able to issue additional calls on the proxy. Note that the client should still close the proxy.
Get Programming WCF Services 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.