Reputation: 45096
What is the most scaleble way to manage state in a WCF.
I just need a single variable to indicate a session and I will manage information relative to the session in a MSSQL. I don't need to know when a session ends. Once a day I will just clear out any old sessions.
It appears SessionID is that variable.
For scale I am using Per Call as the ctor is empty. I don't think I need per session.
In my simple EightBall test I am getting a SessionID that represents a session. But I am just testing on a single box.
What worries me is that I see some documentation that I need to set ReliableSessionBindingElement On and it is Off by default.
Is SessionID going to be a reliable indicator of session in the following configuration?
<system.serviceModel>
<services>
<service name="MajicEightBallServiceLib.MagicEightBallService"
behaviorConfiguration="EightBallServiceMEXBehavior" >
<endpoint address=""
binding="wsHttpBinding"
contract="MajicEightBallServiceLib.IEightBall" />
<endpoint address="mex"
binding ="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/MagicEightBallService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="EightBallServiceMEXBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
[ServiceBehavior (InstanceContextMode=InstanceContextMode.PerCall)]
public class MagicEightBallService : IEightBall
{
public MagicEightBallService()
{
Console.WriteLine("Eightball awaits your question ...");
}
public string ObtainAnswerToQuestion(string userQuestion)
{
return "maybe " + OperationContext.Current.SessionId.ToString();
}
public sDoc GetSdoc(int sID)
{
List<sDocProp> props = new List<sDocProp>();
sDocProp prop1 = new sDocProp { ID = 1, Name = "Prop1", ArrivalStatus = ArrivalStatus.OnTime };
props.Add(prop1);
sDocPropStringSV prop2 = new sDocPropStringSV { ID = 1, Name = "Prop1", ArrivalStatus = ArrivalStatus.OnTime, Value = "StrValue1" };
props.Add(prop2);
sDoc sDoc = new sDoc { sID = sID, sParID = 1, Props = props, SessionID = OperationContext.Current.SessionId.ToString() };
return sDoc;
}
Upvotes: 1
Views: 1745
Reputation: 6008
WCF supports 4 types of sessions and reliable session is only one of them. So you do not necessary need to turn set ReliableSessionBindingElement On to enable session. You can use other session types.
The
System.ServiceModel.Channels.ReliableSessionBindingElement
, which implements the WS-ReliableMessaging specification, provides support for reliable sessions in which messages are delivered in order and exactly once, enabling confidence even when messages travel across multiple nodes during the conversation.
Actually wsHttpBinding
by default uses a secure session which encrypts and digitally signs messages.
Is SessionID going to be a reliable indicator of session in the following configuration?
Service can check if your binding configured to use session using ServiceContractAttribute.SessionMode
attribute.
The following service contract requires that configured bindings use sessions.
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IEightBall
What is the most scaleble way to manage state in a WCF.
InstanceContextMode.PerCall
is the right choice if your code does not depend on any session data except Session ID. Session ID is part of WCF message so there is no need to keep InstanceContext
longer than it is necessary to process request.
Another question:
Is SessionID going to be a reliable indicator of session in the following configuration?
Answer is YES.
Below is reverse-engineered code of property System.ServiceModel.OperationContext.SessionId
. As you can see SessionId
is loaded from Channel.Session
and not empty SessionId
value is returned only if Session
is not null.
public string SessionId
{
get
{
if (this.channel != null)
{
IChannel innerChannel = this.channel.InnerChannel;
if (innerChannel != null)
{
ISessionChannel<IDuplexSession> sessionChannel = innerChannel as ISessionChannel<IDuplexSession>;
if (sessionChannel != null && sessionChannel.Session != null)
{
return sessionChannel.Session.Id;
}
ISessionChannel<IInputSession> sessionChannel2 = innerChannel as ISessionChannel<IInputSession>;
if (sessionChannel2 != null && sessionChannel2.Session != null)
{
return sessionChannel2.Session.Id;
}
ISessionChannel<IOutputSession> sessionChannel3 = innerChannel as ISessionChannel<IOutputSession>;
if (sessionChannel3 != null && sessionChannel3.Session != null)
{
return sessionChannel3.Session.Id;
}
}
}
return null;
}
}
Upvotes: 2